mirror of
https://github.com/MariaDB/server.git
synced 2026-05-16 20:07:13 +02:00
MDEV-5574 Set AUTO_INCREMENT below max value of column.
Update InnoDB to 5.6.14 Apply MySQL-5.6 hack for MySQL Bug#16434374 Move Aria-only HA_RTREE_INDEX from my_base.h to maria_def.h (breaks an assert in InnoDB) Fix InnoDB memory leak
This commit is contained in:
parent
27fbb637d3
commit
27d45e4696
160 changed files with 10282 additions and 5808 deletions
|
|
@ -264,13 +264,11 @@ enum ha_base_keytype {
|
|||
#define HA_SPATIAL 1024 /* For spatial search */
|
||||
#define HA_NULL_ARE_EQUAL 2048 /* NULL in key are cmp as equal */
|
||||
#define HA_GENERATED_KEY 8192 /* Automaticly generated key */
|
||||
#define HA_RTREE_INDEX 16384 /* For RTREE search */
|
||||
|
||||
/* The combination of the above can be used for key type comparison. */
|
||||
#define HA_KEYFLAG_MASK (HA_NOSAME | HA_PACK_KEY | HA_AUTO_KEY | \
|
||||
HA_BINARY_PACK_KEY | HA_FULLTEXT | HA_UNIQUE_CHECK | \
|
||||
HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY | \
|
||||
HA_RTREE_INDEX)
|
||||
HA_SPATIAL | HA_NULL_ARE_EQUAL | HA_GENERATED_KEY)
|
||||
|
||||
/*
|
||||
Key contains partial segments.
|
||||
|
|
|
|||
11
mysql-test/r/alter_table_autoinc-5574.result
Normal file
11
mysql-test/r/alter_table_autoinc-5574.result
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
create table t1(a int(10)unsigned not null auto_increment primary key,
|
||||
b varchar(255) not null) engine=innodb default charset=utf8;
|
||||
insert into t1 values(1,'aaa'),(2,'bbb');
|
||||
alter table t1 auto_increment=1;
|
||||
insert into t1 values(NULL, 'ccc');
|
||||
select * from t1;
|
||||
a b
|
||||
1 aaa
|
||||
2 bbb
|
||||
3 ccc
|
||||
drop table t1;
|
||||
|
|
@ -1597,10 +1597,6 @@ select distinct concat(a, b) from t1;
|
|||
concat(a, b)
|
||||
11113333
|
||||
drop table t1;
|
||||
CREATE TABLE t1 ( a char(10) ) ENGINE=InnoDB;
|
||||
SELECT a FROM t1 WHERE MATCH (a) AGAINST ('test' IN BOOLEAN MODE);
|
||||
ERROR HY000: The table does not have FULLTEXT index to support this query
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1 (a_id tinyint(4) NOT NULL default '0', PRIMARY KEY (a_id)) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
INSERT INTO t1 VALUES (1),(2),(3);
|
||||
CREATE TABLE t2 (b_id tinyint(4) NOT NULL default '0',b_a tinyint(4) NOT NULL default '0', PRIMARY KEY (b_id), KEY (b_a),
|
||||
|
|
|
|||
|
|
@ -1244,16 +1244,6 @@ insert into t1 values ('1111', '3333');
|
|||
select distinct concat(a, b) from t1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
# BUG#7709 test case - Boolean fulltext query against unsupported
|
||||
# engines does not fail
|
||||
#
|
||||
|
||||
CREATE TABLE t1 ( a char(10) ) ENGINE=InnoDB;
|
||||
--error 1764
|
||||
SELECT a FROM t1 WHERE MATCH (a) AGAINST ('test' IN BOOLEAN MODE);
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# check null values #1
|
||||
#
|
||||
|
|
|
|||
|
|
@ -337,9 +337,9 @@ insert into t2 values (1, 1, 'xxfoo');
|
|||
insert into t2 values (2, 1, 'xxbar');
|
||||
insert into t2 values (3, 1, 'xxbuz');
|
||||
select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode);
|
||||
ERROR HY000: The table does not have FULLTEXT index to support this query
|
||||
ERROR HY000: Incorrect arguments to MATCH
|
||||
select * from t2 where match name against ('*a*b*c*d*e*f*' in boolean mode);
|
||||
ERROR HY000: The table does not have FULLTEXT index to support this query
|
||||
ERROR HY000: Can't find FULLTEXT index matching the column list
|
||||
drop table t1,t2;
|
||||
create table t1 (a text, fulltext key (a)) ENGINE = InnoDB;
|
||||
insert into t1 select "xxxx yyyy zzzz";
|
||||
|
|
@ -479,16 +479,13 @@ id select_type table type possible_keys key key_len ref rows Extra
|
|||
1 SIMPLE t1 fulltext a a 0 1 Using where
|
||||
EXPLAIN SELECT * FROM t1 IGNORE INDEX(a)
|
||||
WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL b NULL NULL NULL 8 Using where
|
||||
ERROR HY000: Can't find FULLTEXT index matching the column list
|
||||
EXPLAIN SELECT * FROM t1 USE INDEX(b)
|
||||
WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ALL b NULL NULL NULL 8 Using where
|
||||
ERROR HY000: Can't find FULLTEXT index matching the column list
|
||||
EXPLAIN SELECT * FROM t1 FORCE INDEX(b)
|
||||
WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 ref b b 5 const 5 Using where
|
||||
ERROR HY000: Can't find FULLTEXT index matching the column list
|
||||
DROP TABLE t1;
|
||||
CREATE TABLE t1(a CHAR(10), fulltext(a)) ENGINE = InnoDB;
|
||||
INSERT INTO t1 VALUES('aaa15');
|
||||
|
|
@ -562,14 +559,12 @@ WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
|||
);
|
||||
count(*)
|
||||
1
|
||||
# should return 0
|
||||
SELECT count(*) FROM t1 WHERE
|
||||
not exists(
|
||||
SELECT 1 FROM t2 IGNORE INDEX (b2), t3
|
||||
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||
);
|
||||
count(*)
|
||||
0
|
||||
ERROR HY000: Can't find FULLTEXT index matching the column list
|
||||
DROP TABLE t1,t2,t3;
|
||||
CREATE TABLE t1 (a VARCHAR(4), FULLTEXT(a)) ENGINE = InnoDB;
|
||||
INSERT INTO t1 VALUES
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ create table t2 (m_id int not null, f char(200), key (m_id), fulltext (f)) engin
|
|||
insert into t2 values (1, 'bword'), (3, 'aword'), (5, '');
|
||||
ANALYZE TABLE t2;
|
||||
select * from t1 left join t2 on m_id = id where match(d, e, f) against ('+aword +bword' in boolean mode);
|
||||
id d e m_id f
|
||||
ERROR HY000: Incorrect arguments to MATCH
|
||||
drop table t1,t2;
|
||||
CREATE TABLE t1 (
|
||||
id int(10) NOT NULL auto_increment,
|
||||
|
|
@ -89,9 +89,7 @@ ANALYZE TABLE t2;
|
|||
SELECT t1.*, MATCH(t1.name) AGAINST('string') AS relevance
|
||||
FROM t1 LEFT JOIN t2 ON t1.link = t2.id
|
||||
WHERE MATCH(t1.name, t2.name) AGAINST('string' IN BOOLEAN MODE);
|
||||
id link name relevance
|
||||
1 1 string 0.000000001885928302414186
|
||||
2 0 string 0.000000001885928302414186
|
||||
ERROR HY000: Incorrect arguments to MATCH
|
||||
DROP TABLE t1,t2;
|
||||
CREATE TABLE t1 (a INT) ENGINE = InnoDB;
|
||||
CREATE TABLE t2 (b INT, c TEXT, KEY(b), FULLTEXT(c)) ENGINE = InnoDB;
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ drop table t1, t2;
|
|||
CREATE TABLE t1(a TEXT CHARSET ucs2 COLLATE ucs2_unicode_ci) ENGINE = InnoDB;
|
||||
INSERT INTO t1 VALUES('abcd');
|
||||
SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abcd' IN BOOLEAN MODE);
|
||||
ERROR HY000: The table does not have FULLTEXT index to support this query
|
||||
ERROR HY000: Can't find FULLTEXT index matching the column list
|
||||
DROP TABLE t1;
|
||||
create table t1 (a varchar(10), key(a), fulltext (a)) ENGINE = InnoDB;
|
||||
insert into t1 values ("a"),("abc"),("abcd"),("hello"),("test");
|
||||
|
|
|
|||
|
|
@ -710,8 +710,7 @@ CREATE FULLTEXT INDEX i ON t1 (char_column2);
|
|||
Warnings:
|
||||
Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID
|
||||
SELECT * FROM t1 WHERE MATCH(char_column) AGAINST ('abc*' IN BOOLEAN MODE);
|
||||
id char_column char_column2
|
||||
NULL abcde abcde
|
||||
ERROR HY000: Can't find FULLTEXT index matching the column list
|
||||
DROP TABLE t1;
|
||||
"----------Test22---------"
|
||||
CREATE TABLE t1 ( id INT , char_column VARCHAR(60) CHARACTER SET UTF8) ENGINE = InnoDB;
|
||||
|
|
|
|||
29
mysql-test/suite/innodb_fts/r/innodb_fts_plugin.result
Normal file
29
mysql-test/suite/innodb_fts/r/innodb_fts_plugin.result
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
INSTALL PLUGIN simple_parser SONAME 'mypluglib';
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200),
|
||||
body TEXT,
|
||||
FULLTEXT (title) WITH PARSER simple_parser
|
||||
) ENGINE=MyISAM;
|
||||
ALTER TABLE articles ENGINE=InnoDB;
|
||||
ERROR HY000: Cannot CREATE FULLTEXT INDEX WITH PARSER on InnoDB table
|
||||
DROP TABLE articles;
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200),
|
||||
body TEXT,
|
||||
FULLTEXT (title) WITH PARSER simple_parser
|
||||
) ENGINE=InnoDB;
|
||||
ERROR HY000: Cannot CREATE FULLTEXT INDEX WITH PARSER on InnoDB table
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200),
|
||||
body TEXT,
|
||||
FULLTEXT (title)
|
||||
) ENGINE=InnoDB;
|
||||
ALTER TABLE articles ADD FULLTEXT INDEX (body) WITH PARSER simple_parser;
|
||||
ERROR HY000: Cannot CREATE FULLTEXT INDEX WITH PARSER on InnoDB table
|
||||
CREATE FULLTEXT INDEX ft_index ON articles(body) WITH PARSER simple_parser;
|
||||
ERROR HY000: Cannot CREATE FULLTEXT INDEX WITH PARSER on InnoDB table
|
||||
DROP TABLE articles;
|
||||
UNINSTALL PLUGIN simple_parser;
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
CREATE TABLE t1 (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
a VARCHAR(200),
|
||||
b TEXT
|
||||
) ENGINE= InnoDB;
|
||||
CREATE FULLTEXT INDEX idx on t1 (a,b);
|
||||
Warnings:
|
||||
Warning 124 InnoDB rebuilding table to add column FTS_DOC_ID
|
||||
INSERT INTO t1 (a,b) VALUES
|
||||
('MySQL from Tutorial','DBMS stands for DataBase ...') ,
|
||||
('when To Use MySQL Well','After that you went through a ...'),
|
||||
('where will Optimizing MySQL','what In this tutorial we will show ...'),
|
||||
('MySQL from Tutorial','DBMS stands for DataBase ...') ,
|
||||
('when To Use MySQL Well','After that you went through a ...'),
|
||||
('where will Optimizing MySQL','what In this tutorial we will show ...'),
|
||||
('MySQL from Tutorial','DBMS stands for DataBase ...') ,
|
||||
('when To Use MySQL Well','After that you went through a ...'),
|
||||
('where will Optimizing MySQL','what In this tutorial we will show ...');
|
||||
SET SESSION debug_dbug="+d,fts_instrument_result_cache_limit";
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('mysql' IN BOOLEAN MODE);
|
||||
COUNT(*)
|
||||
9
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('mysql' WITH QUERY EXPANSION);
|
||||
ERROR HY000: Table handler out of memory
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('"mysql database"' IN BOOLEAN MODE);
|
||||
ERROR HY000: Table handler out of memory
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('"mysql database" @ 5' IN BOOLEAN MODE);
|
||||
ERROR HY000: Table handler out of memory
|
||||
SET SESSION debug_dbug="-d,fts_instrument_result_cache_limit";
|
||||
DROP TABLE t1;
|
||||
SET GLOBAL innodb_ft_result_cache_limit=default;
|
||||
321
mysql-test/suite/innodb_fts/r/innodb_fts_stopword_charset.result
Normal file
321
mysql-test/suite/innodb_fts/r/innodb_fts_stopword_charset.result
Normal file
|
|
@ -0,0 +1,321 @@
|
|||
SELECT @@innodb_ft_server_stopword_table;
|
||||
@@innodb_ft_server_stopword_table
|
||||
NULL
|
||||
SELECT @@innodb_ft_enable_stopword;
|
||||
@@innodb_ft_enable_stopword
|
||||
1
|
||||
SELECT @@innodb_ft_user_stopword_table;
|
||||
@@innodb_ft_user_stopword_table
|
||||
NULL
|
||||
SET NAMES utf8;
|
||||
# Test 1 : default latin1_swedish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 2 : latin1_general_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 3 : latin1_spanish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET latin1 COLLATE latin1_spanish_ci;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
5 löve
|
||||
6 LÖVE
|
||||
7 løve
|
||||
8 LØVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET latin1 COLLATE latin1_spanish_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 4 : utf8_general_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
5 löve
|
||||
6 LÖVE
|
||||
9 lṓve
|
||||
10 LṒVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 5 : utf8_unicode_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
9 lṓve
|
||||
10 LṒVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 6 : utf8_unicode_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
5 löve
|
||||
6 LÖVE
|
||||
9 lṓve
|
||||
10 LṒVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 7 : gb2312_chinese_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET gb2312 COLLATE gb2312_chinese_ci;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('相亲相爱'),('怜香惜爱'),('充满可爱'),('爱恨交织');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('相亲相爱' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 相亲相爱
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET gb2312 COLLATE gb2312_chinese_ci;
|
||||
INSERT INTO user_stopword VALUES('相亲相爱');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('相亲相爱' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('怜香惜爱' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
2 怜香惜爱
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 8 : test shutdown to check if stopword still works
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
# Shutdown and restart mysqld
|
||||
SET NAMES utf8;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
# Test 9 : drop user stopwrod table,test shutdown to check if it works
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
1 love
|
||||
2 LOVE
|
||||
3 lòve
|
||||
4 LÒVE
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
DROP TABLE user_stopword;
|
||||
# Shutdown and restart mysqld
|
||||
SET NAMES utf8;
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
11 love
|
||||
12 LOVE
|
||||
13 lòve
|
||||
14 LÒVE
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
id title
|
||||
11 love
|
||||
12 LOVE
|
||||
13 lòve
|
||||
14 LÒVE
|
||||
DROP TABLE articles;
|
||||
SET SESSION innodb_ft_enable_stopword=1;
|
||||
SET GLOBAL innodb_ft_server_stopword_table=default;
|
||||
SET SESSION innodb_ft_user_stopword_table=default;
|
||||
|
|
@ -4,11 +4,6 @@
|
|||
|
||||
--source include/have_innodb.inc
|
||||
|
||||
if (`select plugin_auth_version <= "5.6.10" from information_schema.plugins where plugin_name='innodb'`)
|
||||
{
|
||||
--skip Not fixed in InnoDB 5.6.10 or earlier
|
||||
}
|
||||
|
||||
--disable_warnings
|
||||
drop table if exists t1,t2,t3;
|
||||
--enable_warnings
|
||||
|
|
@ -281,17 +276,17 @@ create table t2 (t2_id int(11) primary key, t1_id int(11), name varchar(32)) ENG
|
|||
insert into t2 values (1, 1, 'xxfoo');
|
||||
insert into t2 values (2, 1, 'xxbar');
|
||||
insert into t2 values (3, 1, 'xxbuz');
|
||||
# INNODB_FTS: Note there is no fulltext index on table. InnoDB do not support
|
||||
# Fulltext search in such case, will return 1739
|
||||
--error ER_TABLE_HAS_NO_FT
|
||||
# INNODB_FTS: InnoDB do not support MATCH expressions with arguments from
|
||||
# different tables
|
||||
--error ER_WRONG_ARGUMENTS
|
||||
select * from t1 join t2 using(`t1_id`) where match (t1.name, t2.name) against('xxfoo' in boolean mode);
|
||||
|
||||
#
|
||||
# Bug #7858: bug with many short (< ft_min_word_len) words in boolean search
|
||||
#
|
||||
# INNODB_FTS: Note there is no fulltext index on table. InnoDB do not support
|
||||
# Fulltext search in such case, will return 1739
|
||||
--error ER_TABLE_HAS_NO_FT
|
||||
# Fulltext search in such case
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
select * from t2 where match name against ('*a*b*c*d*e*f*' in boolean mode);
|
||||
drop table t1,t2;
|
||||
|
||||
|
|
@ -490,12 +485,15 @@ WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
|||
EXPLAIN SELECT * FROM t1 FORCE INDEX(a)
|
||||
WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
||||
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
EXPLAIN SELECT * FROM t1 IGNORE INDEX(a)
|
||||
WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
||||
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
EXPLAIN SELECT * FROM t1 USE INDEX(b)
|
||||
WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
||||
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
EXPLAIN SELECT * FROM t1 FORCE INDEX(b)
|
||||
WHERE MATCH(a) AGAINST('test' IN BOOLEAN MODE) AND b=1;
|
||||
|
||||
|
|
@ -592,7 +590,7 @@ SELECT count(*) FROM t1 WHERE
|
|||
WHERE t3.a=t1.a AND MATCH(b2) AGAINST('scargill' IN BOOLEAN MODE)
|
||||
);
|
||||
|
||||
--echo # should return 0
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
SELECT count(*) FROM t1 WHERE
|
||||
not exists(
|
||||
SELECT 1 FROM t2 IGNORE INDEX (b2), t3
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ insert into t2 values (1, 'bword'), (3, 'aword'), (5, '');
|
|||
-- disable_result_log
|
||||
ANALYZE TABLE t2;
|
||||
-- enable_result_log
|
||||
--error ER_WRONG_ARGUMENTS
|
||||
select * from t1 left join t2 on m_id = id where match(d, e, f) against ('+aword +bword' in boolean mode);
|
||||
drop table t1,t2;
|
||||
|
||||
|
|
@ -107,6 +108,7 @@ ANALYZE TABLE t1;
|
|||
ANALYZE TABLE t2;
|
||||
-- enable_result_log
|
||||
|
||||
--error ER_WRONG_ARGUMENTS
|
||||
SELECT t1.*, MATCH(t1.name) AGAINST('string') AS relevance
|
||||
FROM t1 LEFT JOIN t2 ON t1.link = t2.id
|
||||
WHERE MATCH(t1.name, t2.name) AGAINST('string' IN BOOLEAN MODE);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ CREATE TABLE t1(a TEXT CHARSET ucs2 COLLATE ucs2_unicode_ci) ENGINE = InnoDB;
|
|||
INSERT INTO t1 VALUES('abcd');
|
||||
|
||||
# INNODB_FTS: Please Note this table do not have FTS. InnoDB return 1214 error
|
||||
--error ER_TABLE_HAS_NO_FT
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
SELECT * FROM t1 WHERE MATCH(a) AGAINST ('+abcd' IN BOOLEAN MODE);
|
||||
DROP TABLE t1;
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,7 @@ order by
|
|||
(select b.id, b.betreff from t3 b)
|
||||
order by match(betreff) against ('+abc' in boolean mode) desc;
|
||||
|
||||
--error 1191
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
(select b.id, b.betreff from t3 b) union
|
||||
(select b.id, b.betreff from t3 b)
|
||||
order by match(betreff) against ('+abc') desc;
|
||||
|
|
|
|||
|
|
@ -9,11 +9,6 @@ let collation=UTF8_UNICODE_CI;
|
|||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
|
||||
if (`select plugin_auth_version <= "5.6.10" from information_schema.plugins where plugin_name='innodb'`)
|
||||
{
|
||||
--skip Not fixed in InnoDB 5.6.10 or earlier
|
||||
}
|
||||
|
||||
# Create FTS table
|
||||
CREATE TABLE t1 (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
|
|
@ -643,6 +638,7 @@ CREATE TABLE t1 ( id INT , char_column VARCHAR(60) CHARACTER SET UTF32, char_col
|
|||
INSERT INTO t1 (char_column) VALUES ('abcde'),('fghij'),('klmno'),('qrstu');
|
||||
UPDATE t1 SET char_column2 = char_column;
|
||||
CREATE FULLTEXT INDEX i ON t1 (char_column2);
|
||||
--error ER_FT_MATCHING_KEY_NOT_FOUND
|
||||
SELECT * FROM t1 WHERE MATCH(char_column) AGAINST ('abc*' IN BOOLEAN MODE);
|
||||
DROP TABLE t1;
|
||||
|
||||
|
|
|
|||
45
mysql-test/suite/innodb_fts/t/innodb_fts_plugin.test
Normal file
45
mysql-test/suite/innodb_fts/t/innodb_fts_plugin.test
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
--source include/have_simple_parser.inc
|
||||
--source include/have_innodb.inc
|
||||
|
||||
# Install fts parser plugin
|
||||
INSTALL PLUGIN simple_parser SONAME 'mypluglib';
|
||||
|
||||
# Create a myisam table and alter it to innodb table
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200),
|
||||
body TEXT,
|
||||
FULLTEXT (title) WITH PARSER simple_parser
|
||||
) ENGINE=MyISAM;
|
||||
--error ER_INNODB_NO_FT_USES_PARSER
|
||||
ALTER TABLE articles ENGINE=InnoDB;
|
||||
|
||||
DROP TABLE articles;
|
||||
|
||||
# Create a table having a full text index with parser
|
||||
--error ER_INNODB_NO_FT_USES_PARSER
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200),
|
||||
body TEXT,
|
||||
FULLTEXT (title) WITH PARSER simple_parser
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200),
|
||||
body TEXT,
|
||||
FULLTEXT (title)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# Alter table to add a full text index with parser
|
||||
--error ER_INNODB_NO_FT_USES_PARSER
|
||||
ALTER TABLE articles ADD FULLTEXT INDEX (body) WITH PARSER simple_parser;
|
||||
|
||||
# Create a full text index with parser
|
||||
--error ER_INNODB_NO_FT_USES_PARSER
|
||||
CREATE FULLTEXT INDEX ft_index ON articles(body) WITH PARSER simple_parser;
|
||||
|
||||
DROP TABLE articles;
|
||||
# Uninstall plugin
|
||||
UNINSTALL PLUGIN simple_parser;
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
# This is a basic test for innodb fts result cache limit.
|
||||
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
# Must have debug code to use SET SESSION debug
|
||||
--source include/have_debug.inc
|
||||
|
||||
# Create FTS table
|
||||
CREATE TABLE t1 (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
a VARCHAR(200),
|
||||
b TEXT
|
||||
) ENGINE= InnoDB;
|
||||
|
||||
# Create the FTS index again
|
||||
CREATE FULLTEXT INDEX idx on t1 (a,b);
|
||||
|
||||
# Insert rows
|
||||
INSERT INTO t1 (a,b) VALUES
|
||||
('MySQL from Tutorial','DBMS stands for DataBase ...') ,
|
||||
('when To Use MySQL Well','After that you went through a ...'),
|
||||
('where will Optimizing MySQL','what In this tutorial we will show ...'),
|
||||
('MySQL from Tutorial','DBMS stands for DataBase ...') ,
|
||||
('when To Use MySQL Well','After that you went through a ...'),
|
||||
('where will Optimizing MySQL','what In this tutorial we will show ...'),
|
||||
('MySQL from Tutorial','DBMS stands for DataBase ...') ,
|
||||
('when To Use MySQL Well','After that you went through a ...'),
|
||||
('where will Optimizing MySQL','what In this tutorial we will show ...');
|
||||
|
||||
SET SESSION debug_dbug="+d,fts_instrument_result_cache_limit";
|
||||
|
||||
# Simple term search
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('mysql' IN BOOLEAN MODE);
|
||||
|
||||
# Query expansion
|
||||
--error 128
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('mysql' WITH QUERY EXPANSION);
|
||||
|
||||
# Simple phrase search
|
||||
--error 128
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('"mysql database"' IN BOOLEAN MODE);
|
||||
|
||||
# Simple proximity search
|
||||
--error 128
|
||||
SELECT COUNT(*) FROM t1 WHERE MATCH (a,b) AGAINST ('"mysql database" @ 5' IN BOOLEAN MODE);
|
||||
|
||||
SET SESSION debug_dbug="-d,fts_instrument_result_cache_limit";
|
||||
|
||||
DROP TABLE t1;
|
||||
|
||||
SET GLOBAL innodb_ft_result_cache_limit=default;
|
||||
421
mysql-test/suite/innodb_fts/t/innodb_fts_stopword_charset.test
Normal file
421
mysql-test/suite/innodb_fts/t/innodb_fts_stopword_charset.test
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
# This is the basic function tests for innodb FTS stopword charset
|
||||
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
# Valgrind would complain about memory leaks when we crash on purpose.
|
||||
--source include/not_valgrind.inc
|
||||
# Embedded server does not support crashing
|
||||
--source include/not_embedded.inc
|
||||
# Avoid CrashReporter popup on Mac
|
||||
--source include/not_crashrep.inc
|
||||
|
||||
let $innodb_ft_server_stopword_table_orig=`SELECT @@innodb_ft_server_stopword_table`;
|
||||
let $innodb_ft_enable_stopword_orig=`SELECT @@innodb_ft_enable_stopword`;
|
||||
let $innodb_ft_user_stopword_table_orig=`SELECT @@innodb_ft_user_stopword_table`;
|
||||
|
||||
SELECT @@innodb_ft_server_stopword_table;
|
||||
SELECT @@innodb_ft_enable_stopword;
|
||||
SELECT @@innodb_ft_user_stopword_table;
|
||||
|
||||
SET NAMES utf8;
|
||||
|
||||
-- echo # Test 1 : default latin1_swedish_ci
|
||||
# Create FTS table with default charset latin1_swedish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve' and check result with 'love'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 2 : latin1_general_ci
|
||||
# Create FTS table with default charset latin1_swedish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET latin1 COLLATE latin1_general_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 3 : latin1_spanish_ci
|
||||
# Create FTS table with default charset latin1_swedish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET latin1 COLLATE latin1_spanish_ci;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET latin1 COLLATE latin1_spanish_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 4 : utf8_general_ci
|
||||
# Create FTS table with default charset utf8_general_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 5 : utf8_unicode_ci
|
||||
# Create FTS table with default charset utf8_swedish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_swedish_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 6 : utf8_unicode_ci
|
||||
# Create FTS table with default charset utf8_unicode_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 7 : gb2312_chinese_ci
|
||||
# Create FTS table with default charset gb2312_chinese_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB DEFAULT CHARACTER SET gb2312 COLLATE gb2312_chinese_ci;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('相亲相爱'),('怜香惜爱'),('充满可爱'),('爱恨交织');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find '相亲相爱'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('相亲相爱' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB
|
||||
DEFAULT CHARACTER SET gb2312 COLLATE gb2312_chinese_ci;
|
||||
INSERT INTO user_stopword VALUES('相亲相爱');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find '相亲相爱'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('相亲相爱' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('怜香惜爱' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 8 : test shutdown to check if stopword still works
|
||||
# Create FTS table with default charset latin1_swedish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve' and check result with 'love'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
--echo # Shutdown and restart mysqld
|
||||
--source include/restart_mysqld.inc
|
||||
|
||||
SET NAMES utf8;
|
||||
|
||||
# Insert rows to check if it uses user stopword
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
--enable_warnings
|
||||
|
||||
# Now we will not find 'lòve' and check result with 'love'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
-- echo # Test 9 : drop user stopwrod table,test shutdown to check if it works
|
||||
# Create FTS table with default charset latin1_swedish_ci
|
||||
CREATE TABLE articles (
|
||||
id INT UNSIGNED AUTO_INCREMENT NOT NULL PRIMARY KEY,
|
||||
title VARCHAR(200)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
|
||||
# Build full text index with default stopword
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
--enable_warnings
|
||||
|
||||
# We can find 'lòve'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Define a user stopword table and set to it
|
||||
CREATE TABLE user_stopword(value varchar(30)) ENGINE = InnoDB;
|
||||
INSERT INTO user_stopword VALUES('lòve');
|
||||
SET GLOBAL innodb_ft_server_stopword_table = 'test/user_stopword';
|
||||
|
||||
# Rebuild the full text index with user stopword
|
||||
DROP INDEX ft_idx ON articles;
|
||||
CREATE FULLTEXT INDEX ft_idx ON articles(title);
|
||||
|
||||
# Now we will not find 'lòve' and check result with 'love'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
# Drop user stopword table
|
||||
DROP TABLE user_stopword;
|
||||
|
||||
--echo # Shutdown and restart mysqld
|
||||
--source include/restart_mysqld.inc
|
||||
|
||||
SET NAMES utf8;
|
||||
|
||||
# Insert rows to check if it uses user stopword
|
||||
--disable_warnings
|
||||
INSERT INTO articles (title) VALUES
|
||||
('love'),('LOVE'),('lòve'),('LÒVE'),('löve'),('LÖVE'),('løve'),('LØVE'),
|
||||
('lṓve'),('LṒVE');
|
||||
--enable_warnings
|
||||
|
||||
# Now we will not find 'lòve' and check result with 'love'
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('lòve' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
SELECT * FROM articles WHERE MATCH (title)
|
||||
AGAINST ('love' IN NATURAL LANGUAGE MODE);
|
||||
|
||||
DROP TABLE articles;
|
||||
|
||||
# Restore Values
|
||||
eval SET SESSION innodb_ft_enable_stopword=$innodb_ft_enable_stopword_orig;
|
||||
eval SET GLOBAL innodb_ft_server_stopword_table=default;
|
||||
eval SET SESSION innodb_ft_user_stopword_table=default;
|
||||
12
mysql-test/t/alter_table_autoinc-5574.test
Normal file
12
mysql-test/t/alter_table_autoinc-5574.test
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
#
|
||||
# MDEV-5574 Set AUTO_INCREMENT below max value of column
|
||||
#
|
||||
--source include/have_innodb.inc
|
||||
create table t1(a int(10)unsigned not null auto_increment primary key,
|
||||
b varchar(255) not null) engine=innodb default charset=utf8;
|
||||
insert into t1 values(1,'aaa'),(2,'bbb');
|
||||
alter table t1 auto_increment=1;
|
||||
insert into t1 values(NULL, 'ccc');
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
|
||||
|
|
@ -6214,6 +6214,7 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
bool allows_multi_table_search= true;
|
||||
const_item_cache=0;
|
||||
for (uint i=1 ; i < arg_count ; i++)
|
||||
{
|
||||
|
|
@ -6225,7 +6226,10 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
|
|||
my_error(ER_WRONG_ARGUMENTS, MYF(0), "AGAINST");
|
||||
return TRUE;
|
||||
}
|
||||
allows_multi_table_search &=
|
||||
allows_search_on_non_indexed_columns(((Item_field *)item)->field->table);
|
||||
}
|
||||
|
||||
/*
|
||||
Check that all columns come from the same table.
|
||||
We've already checked that columns in MATCH are fields so
|
||||
|
|
@ -6234,7 +6238,7 @@ bool Item_func_match::fix_fields(THD *thd, Item **ref)
|
|||
if ((used_tables_cache & ~PARAM_TABLE_BIT) != item->used_tables())
|
||||
key=NO_SUCH_KEY;
|
||||
|
||||
if (key == NO_SUCH_KEY && !(flags & FT_BOOL))
|
||||
if (key == NO_SUCH_KEY && !allows_multi_table_search)
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS,MYF(0),"MATCH");
|
||||
return TRUE;
|
||||
|
|
@ -6332,7 +6336,7 @@ bool Item_func_match::fix_index()
|
|||
}
|
||||
|
||||
err:
|
||||
if (flags & FT_BOOL)
|
||||
if (allows_search_on_non_indexed_columns(table))
|
||||
{
|
||||
key=NO_SUCH_KEY;
|
||||
return 0;
|
||||
|
|
|
|||
|
|
@ -1909,6 +1909,41 @@ public:
|
|||
/* TODO: consider adding in support for the MATCH-based virtual columns */
|
||||
return trace_unsupported_by_check_vcol_func_processor(func_name());
|
||||
}
|
||||
private:
|
||||
/**
|
||||
Check whether storage engine for given table,
|
||||
allows FTS Boolean search on non-indexed columns.
|
||||
|
||||
@todo A flag should be added to the extended fulltext API so that
|
||||
it may be checked whether search on non-indexed columns are
|
||||
supported. Currently, it is not possible to check for such a
|
||||
flag since @c this->ft_handler is not yet set when this function is
|
||||
called. The current hack is to assume that search on non-indexed
|
||||
columns are supported for engines that does not support the extended
|
||||
fulltext API (e.g., MyISAM), while it is not supported for other
|
||||
engines (e.g., InnoDB)
|
||||
|
||||
@param table_arg Table for which storage engine to check
|
||||
|
||||
@retval true if BOOLEAN search on non-indexed columns is supported
|
||||
@retval false otherwise
|
||||
*/
|
||||
bool allows_search_on_non_indexed_columns(TABLE* table_arg)
|
||||
{
|
||||
// Only Boolean search may support non_indexed columns
|
||||
if (!(flags & FT_BOOL))
|
||||
return false;
|
||||
|
||||
DBUG_ASSERT(table_arg && table_arg->file);
|
||||
|
||||
// Assume that if extended fulltext API is not supported,
|
||||
// non-indexed columns are allowed. This will be true for MyISAM.
|
||||
if ((table_arg->file->ha_table_flags() & HA_CAN_FULLTEXT_EXT) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2008, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, 2013, 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
|
||||
|
|
@ -245,7 +245,7 @@ ib_open_table_by_id(
|
|||
dict_mutex_enter_for_mysql();
|
||||
}
|
||||
|
||||
table = dict_table_open_on_id(table_id, FALSE, FALSE);
|
||||
table = dict_table_open_on_id(table_id, FALSE, DICT_TABLE_OP_NORMAL);
|
||||
|
||||
if (table != NULL && table->ibd_file_missing) {
|
||||
table = NULL;
|
||||
|
|
@ -1183,7 +1183,7 @@ ib_cursor_open_index_using_name(
|
|||
|
||||
/* We want to increment the ref count, so we do a redundant search. */
|
||||
table = dict_table_open_on_id(cursor->prebuilt->table->id,
|
||||
FALSE, FALSE);
|
||||
FALSE, DICT_TABLE_OP_NORMAL);
|
||||
ut_a(table != NULL);
|
||||
|
||||
/* The first index is always the cluster index. */
|
||||
|
|
@ -1630,6 +1630,8 @@ ib_cursor_insert_row(
|
|||
src_tuple->index->table, q_proc->grph.ins, node->ins);
|
||||
}
|
||||
|
||||
srv_active_wake_master_thread();
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
|
@ -1914,6 +1916,8 @@ ib_cursor_update_row(
|
|||
err = ib_execute_update_query_graph(cursor, pcur);
|
||||
}
|
||||
|
||||
srv_active_wake_master_thread();
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
|
@ -2039,6 +2043,8 @@ ib_cursor_delete_row(
|
|||
err = DB_RECORD_NOT_FOUND;
|
||||
}
|
||||
|
||||
srv_active_wake_master_thread();
|
||||
|
||||
return(err);
|
||||
}
|
||||
|
||||
|
|
@ -2296,12 +2302,14 @@ ib_col_set_value(
|
|||
ib_tpl_t ib_tpl, /*!< in: tuple instance */
|
||||
ib_ulint_t col_no, /*!< in: column index in tuple */
|
||||
const void* src, /*!< in: data value */
|
||||
ib_ulint_t len) /*!< in: data value len */
|
||||
ib_ulint_t len, /*!< in: data value len */
|
||||
ib_bool_t need_cpy) /*!< in: if need memcpy */
|
||||
{
|
||||
const dtype_t* dtype;
|
||||
dfield_t* dfield;
|
||||
void* dst = NULL;
|
||||
ib_tuple_t* tuple = (ib_tuple_t*) ib_tpl;
|
||||
ulint col_len;
|
||||
|
||||
dfield = ib_col_get_dfield(tuple, col_no);
|
||||
|
||||
|
|
@ -2312,6 +2320,7 @@ ib_col_set_value(
|
|||
}
|
||||
|
||||
dtype = dfield_get_type(dfield);
|
||||
col_len = dtype_get_len(dtype);
|
||||
|
||||
/* Not allowed to update system columns. */
|
||||
if (dtype_get_mtype(dtype) == DATA_SYS) {
|
||||
|
|
@ -2325,10 +2334,10 @@ ib_col_set_value(
|
|||
for that. */
|
||||
if (ib_col_is_capped(dtype)) {
|
||||
|
||||
len = ut_min(len, dtype_get_len(dtype));
|
||||
len = ut_min(len, col_len);
|
||||
|
||||
if (dst == NULL || len > dfield_get_len(dfield)) {
|
||||
dst = mem_heap_alloc(tuple->heap, dtype_get_len(dtype));
|
||||
dst = mem_heap_alloc(tuple->heap, col_len);
|
||||
ut_a(dst != NULL);
|
||||
}
|
||||
} else if (dst == NULL || len > dfield_get_len(dfield)) {
|
||||
|
|
@ -2342,7 +2351,7 @@ ib_col_set_value(
|
|||
switch (dtype_get_mtype(dtype)) {
|
||||
case DATA_INT: {
|
||||
|
||||
if (dtype_get_len(dtype) == len) {
|
||||
if (col_len == len) {
|
||||
ibool usign;
|
||||
|
||||
usign = dtype_get_prtype(dtype) & DATA_UNSIGNED;
|
||||
|
|
@ -2387,23 +2396,97 @@ ib_col_set_value(
|
|||
|
||||
memset((byte*) dst + len,
|
||||
pad_char,
|
||||
dtype_get_len(dtype) - len);
|
||||
col_len - len);
|
||||
|
||||
memcpy(dst, src, len);
|
||||
|
||||
len = dtype_get_len(dtype);
|
||||
len = col_len;
|
||||
break;
|
||||
}
|
||||
case DATA_BLOB:
|
||||
case DATA_BINARY:
|
||||
case DATA_MYSQL:
|
||||
case DATA_DECIMAL:
|
||||
case DATA_VARCHAR:
|
||||
case DATA_VARMYSQL:
|
||||
case DATA_FIXBINARY:
|
||||
if (need_cpy) {
|
||||
memcpy(dst, src, len);
|
||||
} else {
|
||||
dfield_set_data(dfield, src, len);
|
||||
dst = dfield_get_data(dfield);
|
||||
}
|
||||
break;
|
||||
|
||||
case DATA_MYSQL:
|
||||
case DATA_VARMYSQL: {
|
||||
ulint cset;
|
||||
CHARSET_INFO* cs;
|
||||
int error = 0;
|
||||
ulint true_len = len;
|
||||
|
||||
/* For multi byte character sets we need to
|
||||
calculate the true length of the data. */
|
||||
cset = dtype_get_charset_coll(
|
||||
dtype_get_prtype(dtype));
|
||||
cs = all_charsets[cset];
|
||||
if (cs) {
|
||||
uint pos = (uint)(col_len / cs->mbmaxlen);
|
||||
|
||||
if (len > 0 && cs->mbmaxlen > 1) {
|
||||
true_len = (ulint)
|
||||
cs->cset->well_formed_len(
|
||||
cs,
|
||||
(const char*)src,
|
||||
(const char*)src + len,
|
||||
pos,
|
||||
&error);
|
||||
|
||||
if (true_len < len) {
|
||||
len = true_len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* All invalid bytes in data need be truncated.
|
||||
If len == 0, means all bytes of the data is invalid.
|
||||
In this case, the data will be truncated to empty.*/
|
||||
memcpy(dst, src, len);
|
||||
|
||||
/* For DATA_MYSQL, need to pad the unused
|
||||
space with spaces. */
|
||||
if (dtype_get_mtype(dtype) == DATA_MYSQL) {
|
||||
ulint n_chars;
|
||||
|
||||
if (len < col_len) {
|
||||
ulint pad_len = col_len - len;
|
||||
|
||||
ut_a(cs != NULL);
|
||||
ut_a(!(pad_len % cs->mbminlen));
|
||||
|
||||
cs->cset->fill(cs, (char*)dst + len,
|
||||
pad_len,
|
||||
0x20 /* space */);
|
||||
}
|
||||
|
||||
/* Why we should do below? See function
|
||||
row_mysql_store_col_in_innobase_format */
|
||||
|
||||
ut_a(!(dtype_get_len(dtype)
|
||||
% dtype_get_mbmaxlen(dtype)));
|
||||
|
||||
n_chars = dtype_get_len(dtype)
|
||||
/ dtype_get_mbmaxlen(dtype);
|
||||
|
||||
/* Strip space padding. */
|
||||
while (col_len > n_chars
|
||||
&& ((char*)dst)[col_len - 1] == 0x20) {
|
||||
col_len--;
|
||||
}
|
||||
|
||||
len = col_len;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
ut_error;
|
||||
}
|
||||
|
|
@ -2476,7 +2559,9 @@ ib_col_copy_value_low(
|
|||
data_len, usign);
|
||||
|
||||
if (usign) {
|
||||
if (len == 2) {
|
||||
if (len == 1) {
|
||||
*(ib_i8_t*)dst = (ib_i8_t)ret;
|
||||
} else if (len == 2) {
|
||||
*(ib_i16_t*)dst = (ib_i16_t)ret;
|
||||
} else if (len == 4) {
|
||||
*(ib_i32_t*)dst = (ib_i32_t)ret;
|
||||
|
|
@ -2484,7 +2569,9 @@ ib_col_copy_value_low(
|
|||
*(ib_i64_t*)dst = (ib_i64_t)ret;
|
||||
}
|
||||
} else {
|
||||
if (len == 2) {
|
||||
if (len == 1) {
|
||||
*(ib_u8_t*)dst = (ib_i8_t)ret;
|
||||
} else if (len == 2) {
|
||||
*(ib_u16_t*)dst = (ib_i16_t)ret;
|
||||
} else if (len == 4) {
|
||||
*(ib_u32_t*)dst = (ib_i32_t)ret;
|
||||
|
|
@ -3450,7 +3537,7 @@ ib_tuple_write_int(
|
|||
return(DB_DATA_MISMATCH);
|
||||
}
|
||||
|
||||
return(ib_col_set_value(ib_tpl, col_no, value, type_len));
|
||||
return(ib_col_set_value(ib_tpl, col_no, value, type_len, true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3465,7 +3552,7 @@ ib_tuple_write_i8(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_i8_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3480,7 +3567,7 @@ ib_tuple_write_i16(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_i16_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3495,7 +3582,7 @@ ib_tuple_write_i32(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_i32_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3510,7 +3597,7 @@ ib_tuple_write_i64(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_i64_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3525,7 +3612,7 @@ ib_tuple_write_u8(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_u8_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3540,7 +3627,7 @@ ib_tuple_write_u16(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_u16_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3555,7 +3642,7 @@ ib_tuple_write_u32(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_u32_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3570,7 +3657,7 @@ ib_tuple_write_u64(
|
|||
int col_no, /*!< in: column number */
|
||||
ib_u64_t val) /*!< in: value to write */
|
||||
{
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val), true));
|
||||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
|
|
@ -3603,7 +3690,8 @@ ib_tuple_write_double(
|
|||
dfield = ib_col_get_dfield(tuple, col_no);
|
||||
|
||||
if (dtype_get_mtype(dfield_get_type(dfield)) == DATA_DOUBLE) {
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no,
|
||||
&val, sizeof(val), true));
|
||||
} else {
|
||||
return(DB_DATA_MISMATCH);
|
||||
}
|
||||
|
|
@ -3653,7 +3741,8 @@ ib_tuple_write_float(
|
|||
dfield = ib_col_get_dfield(tuple, col_no);
|
||||
|
||||
if (dtype_get_mtype(dfield_get_type(dfield)) == DATA_FLOAT) {
|
||||
return(ib_col_set_value(ib_tpl, col_no, &val, sizeof(val)));
|
||||
return(ib_col_set_value(ib_tpl, col_no,
|
||||
&val, sizeof(val), true));
|
||||
} else {
|
||||
return(DB_DATA_MISMATCH);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
@ -44,7 +44,21 @@ Created 6/2/1994 Heikki Tuuri
|
|||
#include "trx0trx.h"
|
||||
#include "srv0mon.h"
|
||||
|
||||
/**************************************************************//**
|
||||
Checks if the page in the cursor can be merged with given page.
|
||||
If necessary, re-organize the merge_page.
|
||||
@return TRUE if possible to merge. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
btr_can_merge_with_page(
|
||||
/*====================*/
|
||||
btr_cur_t* cursor, /*!< in: cursor on the page to merge */
|
||||
ulint page_no, /*!< in: a sibling page */
|
||||
buf_block_t** merge_block, /*!< out: the merge block */
|
||||
mtr_t* mtr); /*!< in: mini-transaction */
|
||||
|
||||
#endif /* UNIV_HOTBACKUP */
|
||||
|
||||
/**************************************************************//**
|
||||
Report that an index page is corrupted. */
|
||||
UNIV_INTERN
|
||||
|
|
@ -1032,7 +1046,7 @@ btr_page_create(
|
|||
btr_blob_dbg_assert_empty(index, buf_block_get_page_no(block));
|
||||
|
||||
if (page_zip) {
|
||||
page_create_zip(block, index, level, mtr);
|
||||
page_create_zip(block, index, level, 0, mtr);
|
||||
} else {
|
||||
page_create(block, mtr, dict_table_is_comp(index->table));
|
||||
/* Set the level of the new index page */
|
||||
|
|
@ -1602,7 +1616,7 @@ btr_create(
|
|||
page_zip = buf_block_get_page_zip(block);
|
||||
|
||||
if (page_zip) {
|
||||
page = page_create_zip(block, index, 0, mtr);
|
||||
page = page_create_zip(block, index, 0, 0, mtr);
|
||||
} else {
|
||||
page = page_create(block, mtr,
|
||||
dict_table_is_comp(index->table));
|
||||
|
|
@ -1727,22 +1741,32 @@ btr_free_root(
|
|||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
/*************************************************************//**
|
||||
Reorganizes an index page. */
|
||||
static
|
||||
ibool
|
||||
Reorganizes an index page.
|
||||
|
||||
IMPORTANT: On success, the caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index. This has to
|
||||
be done either within the same mini-transaction, or by invoking
|
||||
ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
|
||||
IBUF_BITMAP_FREE is unaffected by reorganization.
|
||||
|
||||
@retval true if the operation was successful
|
||||
@retval false if it is a compressed page, and recompression failed */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
btr_page_reorganize_low(
|
||||
/*====================*/
|
||||
ibool recovery,/*!< in: TRUE if called in recovery:
|
||||
bool recovery,/*!< in: true if called in recovery:
|
||||
locks should not be updated, i.e.,
|
||||
there cannot exist locks on the
|
||||
page, and a hash index should not be
|
||||
dropped: it cannot exist */
|
||||
ulint compression_level,/*!< in: compression level to be used
|
||||
ulint z_level,/*!< in: compression level to be used
|
||||
if dealing with compressed page */
|
||||
buf_block_t* block, /*!< in: page to be reorganized */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
mtr_t* mtr) /*!< in: mtr */
|
||||
page_cur_t* cursor, /*!< in/out: page cursor */
|
||||
dict_index_t* index, /*!< in: the index tree of the page */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
{
|
||||
buf_block_t* block = page_cur_get_block(cursor);
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(&block->page);
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
|
@ -1755,9 +1779,9 @@ btr_page_reorganize_low(
|
|||
ulint data_size2;
|
||||
ulint max_ins_size1;
|
||||
ulint max_ins_size2;
|
||||
ibool success = FALSE;
|
||||
byte type;
|
||||
byte* log_ptr;
|
||||
bool success = false;
|
||||
ulint pos;
|
||||
bool log_compressed;
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
||||
btr_assert_not_corrupted(block, index);
|
||||
|
|
@ -1767,27 +1791,6 @@ btr_page_reorganize_low(
|
|||
data_size1 = page_get_data_size(page);
|
||||
max_ins_size1 = page_get_max_insert_size_after_reorganize(page, 1);
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/* Write the log record */
|
||||
if (page_zip) {
|
||||
type = MLOG_ZIP_PAGE_REORGANIZE;
|
||||
} else if (page_is_comp(page)) {
|
||||
type = MLOG_COMP_PAGE_REORGANIZE;
|
||||
} else {
|
||||
type = MLOG_PAGE_REORGANIZE;
|
||||
}
|
||||
|
||||
log_ptr = mlog_open_and_write_index(
|
||||
mtr, page, index, type, page_zip ? 1 : 0);
|
||||
|
||||
/* For compressed pages write the compression level. */
|
||||
if (log_ptr && page_zip) {
|
||||
mach_write_to_1(log_ptr, compression_level);
|
||||
mlog_close(mtr, log_ptr + 1);
|
||||
}
|
||||
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
/* Turn logging off */
|
||||
log_mode = mtr_set_log_mode(mtr, MTR_LOG_NONE);
|
||||
|
||||
|
|
@ -1811,6 +1814,9 @@ btr_page_reorganize_low(
|
|||
#endif /* !UNIV_HOTBACKUP */
|
||||
btr_blob_dbg_remove(page, index, "btr_page_reorganize");
|
||||
|
||||
/* Save the cursor position. */
|
||||
pos = page_rec_get_n_recs_before(page_cur_get_rec(cursor));
|
||||
|
||||
/* Recreate the page: note that global data on page (possible
|
||||
segment headers, next page-field, etc.) is preserved intact */
|
||||
|
||||
|
|
@ -1828,14 +1834,21 @@ btr_page_reorganize_low(
|
|||
trx_id_t max_trx_id = page_get_max_trx_id(temp_page);
|
||||
page_set_max_trx_id(block, NULL, max_trx_id, mtr);
|
||||
/* In crash recovery, dict_index_is_sec_or_ibuf() always
|
||||
returns TRUE, even for clustered indexes. max_trx_id is
|
||||
holds, even for clustered indexes. max_trx_id is
|
||||
unused in clustered index pages. */
|
||||
ut_ad(max_trx_id != 0 || recovery);
|
||||
}
|
||||
|
||||
/* If innodb_log_compressed_pages is ON, page reorganize should log the
|
||||
compressed page image.*/
|
||||
log_compressed = page_zip && page_zip_log_pages;
|
||||
|
||||
if (log_compressed) {
|
||||
mtr_set_log_mode(mtr, log_mode);
|
||||
}
|
||||
|
||||
if (page_zip
|
||||
&& !page_zip_compress(page_zip, page, index,
|
||||
compression_level, NULL)) {
|
||||
&& !page_zip_compress(page_zip, page, index, z_level, mtr)) {
|
||||
|
||||
/* Restore the old page and exit. */
|
||||
btr_blob_dbg_restore(page, temp_page, index,
|
||||
|
|
@ -1890,7 +1903,14 @@ btr_page_reorganize_low(
|
|||
(unsigned long) max_ins_size2);
|
||||
ut_ad(0);
|
||||
} else {
|
||||
success = TRUE;
|
||||
success = true;
|
||||
}
|
||||
|
||||
/* Restore the cursor position. */
|
||||
if (pos > 0) {
|
||||
cursor->rec = page_rec_get_nth(page, pos);
|
||||
} else {
|
||||
ut_ad(cursor->rec == page_get_infimum_rec(page));
|
||||
}
|
||||
|
||||
func_exit:
|
||||
|
|
@ -1904,27 +1924,92 @@ func_exit:
|
|||
/* Restore logging mode */
|
||||
mtr_set_log_mode(mtr, log_mode);
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
if (success) {
|
||||
byte type;
|
||||
byte* log_ptr;
|
||||
|
||||
/* Write the log record */
|
||||
if (page_zip) {
|
||||
ut_ad(page_is_comp(page));
|
||||
type = MLOG_ZIP_PAGE_REORGANIZE;
|
||||
} else if (page_is_comp(page)) {
|
||||
type = MLOG_COMP_PAGE_REORGANIZE;
|
||||
} else {
|
||||
type = MLOG_PAGE_REORGANIZE;
|
||||
}
|
||||
|
||||
log_ptr = log_compressed
|
||||
? NULL
|
||||
: mlog_open_and_write_index(
|
||||
mtr, page, index, type,
|
||||
page_zip ? 1 : 0);
|
||||
|
||||
/* For compressed pages write the compression level. */
|
||||
if (log_ptr && page_zip) {
|
||||
mach_write_to_1(log_ptr, z_level);
|
||||
mlog_close(mtr, log_ptr + 1);
|
||||
}
|
||||
}
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
return(success);
|
||||
}
|
||||
|
||||
/*************************************************************//**
|
||||
Reorganizes an index page.
|
||||
|
||||
IMPORTANT: On success, the caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index. This has to
|
||||
be done either within the same mini-transaction, or by invoking
|
||||
ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
|
||||
IBUF_BITMAP_FREE is unaffected by reorganization.
|
||||
|
||||
@retval true if the operation was successful
|
||||
@retval false if it is a compressed page, and recompression failed */
|
||||
static __attribute__((nonnull))
|
||||
bool
|
||||
btr_page_reorganize_block(
|
||||
/*======================*/
|
||||
bool recovery,/*!< in: true if called in recovery:
|
||||
locks should not be updated, i.e.,
|
||||
there cannot exist locks on the
|
||||
page, and a hash index should not be
|
||||
dropped: it cannot exist */
|
||||
ulint z_level,/*!< in: compression level to be used
|
||||
if dealing with compressed page */
|
||||
buf_block_t* block, /*!< in/out: B-tree page */
|
||||
dict_index_t* index, /*!< in: the index tree of the page */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
{
|
||||
page_cur_t cur;
|
||||
page_cur_set_before_first(block, &cur);
|
||||
|
||||
return(btr_page_reorganize_low(recovery, z_level, &cur, index, mtr));
|
||||
}
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/*************************************************************//**
|
||||
Reorganizes an index page.
|
||||
IMPORTANT: if btr_page_reorganize() is invoked on a compressed leaf
|
||||
page of a non-clustered index, the caller must update the insert
|
||||
buffer free bits in the same mini-transaction in such a way that the
|
||||
modification will be redo-logged.
|
||||
@return TRUE on success, FALSE on failure */
|
||||
|
||||
IMPORTANT: On success, the caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index. This has to
|
||||
be done either within the same mini-transaction, or by invoking
|
||||
ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
|
||||
IBUF_BITMAP_FREE is unaffected by reorganization.
|
||||
|
||||
@retval true if the operation was successful
|
||||
@retval false if it is a compressed page, and recompression failed */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
bool
|
||||
btr_page_reorganize(
|
||||
/*================*/
|
||||
buf_block_t* block, /*!< in: page to be reorganized */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
mtr_t* mtr) /*!< in: mtr */
|
||||
page_cur_t* cursor, /*!< in/out: page cursor */
|
||||
dict_index_t* index, /*!< in: the index tree of the page */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
{
|
||||
return(btr_page_reorganize_low(FALSE, page_compression_level,
|
||||
block, index, mtr));
|
||||
return(btr_page_reorganize_low(false, page_zip_level,
|
||||
cursor, index, mtr));
|
||||
}
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
|
|
@ -1942,7 +2027,7 @@ btr_parse_page_reorganize(
|
|||
buf_block_t* block, /*!< in: page to be reorganized, or NULL */
|
||||
mtr_t* mtr) /*!< in: mtr or NULL */
|
||||
{
|
||||
ulint level = page_compression_level;
|
||||
ulint level;
|
||||
|
||||
ut_ad(ptr && end_ptr);
|
||||
|
||||
|
|
@ -1954,14 +2039,16 @@ btr_parse_page_reorganize(
|
|||
return(NULL);
|
||||
}
|
||||
|
||||
level = (ulint)mach_read_from_1(ptr);
|
||||
level = mach_read_from_1(ptr);
|
||||
|
||||
ut_a(level <= 9);
|
||||
++ptr;
|
||||
} else {
|
||||
level = page_zip_level;
|
||||
}
|
||||
|
||||
if (block != NULL) {
|
||||
btr_page_reorganize_low(TRUE, level, block, index, mtr);
|
||||
btr_page_reorganize_block(true, level, block, index, mtr);
|
||||
}
|
||||
|
||||
return(ptr);
|
||||
|
|
@ -1995,7 +2082,7 @@ btr_page_empty(
|
|||
segment headers, next page-field, etc.) is preserved intact */
|
||||
|
||||
if (page_zip) {
|
||||
page_create_zip(block, index, level, mtr);
|
||||
page_create_zip(block, index, level, 0, mtr);
|
||||
} else {
|
||||
page_create(block, mtr, dict_table_is_comp(index->table));
|
||||
btr_page_set_level(page, NULL, level, mtr);
|
||||
|
|
@ -2043,7 +2130,7 @@ btr_root_raise_and_insert(
|
|||
root = btr_cur_get_page(cursor);
|
||||
root_block = btr_cur_get_block(cursor);
|
||||
root_page_zip = buf_block_get_page_zip(root_block);
|
||||
ut_ad(page_get_n_recs(root) > 0);
|
||||
ut_ad(!page_is_empty(root));
|
||||
index = btr_cur_get_index(cursor);
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
ut_a(!root_page_zip || page_zip_validate(root_page_zip, root, index));
|
||||
|
|
@ -2779,7 +2866,7 @@ func_start:
|
|||
page_zip = buf_block_get_page_zip(block);
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(page_get_n_recs(page) >= 1);
|
||||
ut_ad(!page_is_empty(page));
|
||||
|
||||
page_no = buf_block_get_page_no(block);
|
||||
|
||||
|
|
@ -3033,15 +3120,16 @@ insert_empty:
|
|||
goto func_exit;
|
||||
}
|
||||
|
||||
/* 8. If insert did not fit, try page reorganization */
|
||||
/* 8. If insert did not fit, try page reorganization.
|
||||
For compressed pages, page_cur_tuple_insert() will have
|
||||
attempted this already. */
|
||||
|
||||
if (!btr_page_reorganize(insert_block, cursor->index, mtr)) {
|
||||
if (page_cur_get_page_zip(page_cursor)
|
||||
|| !btr_page_reorganize(page_cursor, cursor->index, mtr)) {
|
||||
|
||||
goto insert_failed;
|
||||
}
|
||||
|
||||
page_cur_search(insert_block, cursor->index, tuple,
|
||||
PAGE_CUR_LE, page_cursor);
|
||||
rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
|
||||
offsets, heap, n_ext, mtr);
|
||||
|
||||
|
|
@ -3049,9 +3137,10 @@ insert_empty:
|
|||
/* The insert did not fit on the page: loop back to the
|
||||
start of the function for a new split */
|
||||
insert_failed:
|
||||
/* We play safe and reset the free bits for new_page */
|
||||
/* We play safe and reset the free bits */
|
||||
if (!dict_index_is_clust(cursor->index)) {
|
||||
ibuf_reset_free_bits(new_block);
|
||||
ibuf_reset_free_bits(block);
|
||||
}
|
||||
|
||||
/* fprintf(stderr, "Split second round %lu\n",
|
||||
|
|
@ -3461,7 +3550,7 @@ btr_compress(
|
|||
ulint left_page_no;
|
||||
ulint right_page_no;
|
||||
buf_block_t* merge_block;
|
||||
page_t* merge_page;
|
||||
page_t* merge_page = NULL;
|
||||
page_zip_des_t* merge_page_zip;
|
||||
ibool is_left;
|
||||
buf_block_t* block;
|
||||
|
|
@ -3469,11 +3558,8 @@ btr_compress(
|
|||
btr_cur_t father_cursor;
|
||||
mem_heap_t* heap;
|
||||
ulint* offsets;
|
||||
ulint data_size;
|
||||
ulint n_recs;
|
||||
ulint nth_rec = 0; /* remove bogus warning */
|
||||
ulint max_ins_size;
|
||||
ulint max_ins_size_reorg;
|
||||
DBUG_ENTER("btr_compress");
|
||||
|
||||
block = btr_cur_get_block(cursor);
|
||||
page = btr_cur_get_page(cursor);
|
||||
|
|
@ -3490,10 +3576,13 @@ btr_compress(
|
|||
left_page_no = btr_page_get_prev(page, mtr);
|
||||
right_page_no = btr_page_get_next(page, mtr);
|
||||
|
||||
#if 0
|
||||
fprintf(stderr, "Merge left page %lu right %lu \n",
|
||||
left_page_no, right_page_no);
|
||||
#endif
|
||||
#ifdef UNIV_DEBUG
|
||||
if (!page_is_leaf(page) && left_page_no == FIL_NULL) {
|
||||
ut_a(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
|
||||
page_rec_get_next(page_get_infimum_rec(page)),
|
||||
page_is_comp(page)));
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
heap = mem_heap_create(100);
|
||||
offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
|
||||
|
|
@ -3504,30 +3593,7 @@ btr_compress(
|
|||
ut_ad(nth_rec > 0);
|
||||
}
|
||||
|
||||
/* Decide the page to which we try to merge and which will inherit
|
||||
the locks */
|
||||
|
||||
is_left = left_page_no != FIL_NULL;
|
||||
|
||||
if (is_left) {
|
||||
|
||||
merge_block = btr_block_get(space, zip_size, left_page_no,
|
||||
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)
|
||||
== buf_block_get_page_no(block));
|
||||
#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, index, mtr);
|
||||
merge_page = buf_block_get_frame(merge_block);
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
ut_a(btr_page_get_prev(merge_page, mtr)
|
||||
== buf_block_get_page_no(block));
|
||||
#endif /* UNIV_BTR_DEBUG */
|
||||
} else {
|
||||
if (left_page_no == FIL_NULL && right_page_no == FIL_NULL) {
|
||||
/* The page is the only one on the level, lift the records
|
||||
to the father */
|
||||
|
||||
|
|
@ -3535,66 +3601,34 @@ btr_compress(
|
|||
goto func_exit;
|
||||
}
|
||||
|
||||
n_recs = page_get_n_recs(page);
|
||||
data_size = page_get_data_size(page);
|
||||
/* Decide the page to which we try to merge and which will inherit
|
||||
the locks */
|
||||
|
||||
is_left = btr_can_merge_with_page(cursor, left_page_no,
|
||||
&merge_block, mtr);
|
||||
|
||||
DBUG_EXECUTE_IF("ib_always_merge_right", is_left = FALSE;);
|
||||
|
||||
if(!is_left
|
||||
&& !btr_can_merge_with_page(cursor, right_page_no, &merge_block,
|
||||
mtr)) {
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
merge_page = buf_block_get_frame(merge_block);
|
||||
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
ut_a(page_is_comp(merge_page) == page_is_comp(page));
|
||||
if (is_left) {
|
||||
ut_a(btr_page_get_next(merge_page, mtr)
|
||||
== buf_block_get_page_no(block));
|
||||
} else {
|
||||
ut_a(btr_page_get_prev(merge_page, mtr)
|
||||
== buf_block_get_page_no(block));
|
||||
}
|
||||
#endif /* UNIV_BTR_DEBUG */
|
||||
|
||||
max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
|
||||
merge_page, n_recs);
|
||||
if (data_size > max_ins_size_reorg) {
|
||||
|
||||
/* No space for merge */
|
||||
err_exit:
|
||||
/* We play it safe and reset the free bits. */
|
||||
if (zip_size
|
||||
&& page_is_leaf(merge_page)
|
||||
&& !dict_index_is_clust(index)) {
|
||||
ibuf_reset_free_bits(merge_block);
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/* If compression padding tells us that merging will result in
|
||||
too packed up page i.e.: which is likely to cause compression
|
||||
failure then don't merge the pages. */
|
||||
if (zip_size && page_is_leaf(merge_page)
|
||||
&& (page_get_data_size(merge_page) + data_size
|
||||
>= dict_index_zip_pad_optimal_page_size(index))) {
|
||||
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
ut_ad(page_validate(merge_page, index));
|
||||
|
||||
max_ins_size = page_get_max_insert_size(merge_page, n_recs);
|
||||
|
||||
if (data_size > max_ins_size) {
|
||||
|
||||
/* We have to reorganize merge_page */
|
||||
|
||||
if (!btr_page_reorganize(merge_block, index, mtr)) {
|
||||
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
max_ins_size = page_get_max_insert_size(merge_page, n_recs);
|
||||
|
||||
ut_ad(page_validate(merge_page, index));
|
||||
ut_ad(max_ins_size == max_ins_size_reorg);
|
||||
|
||||
if (data_size > max_ins_size) {
|
||||
|
||||
/* Add fault tolerance, though this should
|
||||
never happen */
|
||||
|
||||
goto err_exit;
|
||||
}
|
||||
}
|
||||
|
||||
merge_page_zip = buf_block_get_page_zip(merge_block);
|
||||
#ifdef UNIV_ZIP_DEBUG
|
||||
if (merge_page_zip) {
|
||||
|
|
@ -3629,11 +3663,19 @@ err_exit:
|
|||
}
|
||||
} else {
|
||||
rec_t* orig_succ;
|
||||
ibool compressed;
|
||||
dberr_t err;
|
||||
btr_cur_t cursor2;
|
||||
/* father cursor pointing to node ptr
|
||||
of the right sibling */
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
byte fil_page_prev[4];
|
||||
#endif /* UNIV_BTR_DEBUG */
|
||||
|
||||
if (merge_page_zip) {
|
||||
btr_page_get_father(index, merge_block, mtr, &cursor2);
|
||||
|
||||
if (merge_page_zip && left_page_no == FIL_NULL) {
|
||||
|
||||
/* The function page_zip_compress(), which will be
|
||||
invoked by page_copy_rec_list_end() below,
|
||||
requires that FIL_PAGE_PREV be FIL_NULL.
|
||||
|
|
@ -3654,9 +3696,12 @@ err_exit:
|
|||
if (!orig_succ) {
|
||||
ut_a(merge_page_zip);
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
/* FIL_PAGE_PREV was restored from merge_page_zip. */
|
||||
if (left_page_no == FIL_NULL) {
|
||||
/* FIL_PAGE_PREV was restored from
|
||||
merge_page_zip. */
|
||||
ut_a(!memcmp(fil_page_prev,
|
||||
merge_page + FIL_PAGE_PREV, 4));
|
||||
}
|
||||
#endif /* UNIV_BTR_DEBUG */
|
||||
goto err_exit;
|
||||
}
|
||||
|
|
@ -3664,7 +3709,8 @@ err_exit:
|
|||
btr_search_drop_page_hash_index(block);
|
||||
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
if (merge_page_zip) {
|
||||
if (merge_page_zip && left_page_no == FIL_NULL) {
|
||||
|
||||
/* Restore FIL_PAGE_PREV in order to avoid an assertion
|
||||
failure in btr_level_list_remove(), which will set
|
||||
the field again to FIL_NULL. Even though this makes
|
||||
|
|
@ -3680,12 +3726,19 @@ err_exit:
|
|||
|
||||
/* Replace the address of the old child node (= page) with the
|
||||
address of the merge page to the right */
|
||||
|
||||
btr_node_ptr_set_child_page_no(
|
||||
btr_cur_get_rec(&father_cursor),
|
||||
btr_cur_get_page_zip(&father_cursor),
|
||||
offsets, right_page_no, mtr);
|
||||
btr_node_ptr_delete(index, merge_block, mtr);
|
||||
|
||||
compressed = btr_cur_pessimistic_delete(&err, TRUE, &cursor2,
|
||||
BTR_CREATE_FLAG,
|
||||
RB_NONE, mtr);
|
||||
ut_a(err == DB_SUCCESS);
|
||||
|
||||
if (!compressed) {
|
||||
btr_cur_compress_if_useful(&cursor2, FALSE, mtr);
|
||||
}
|
||||
|
||||
lock_update_merge_right(merge_block, orig_succ, block);
|
||||
}
|
||||
|
|
@ -3753,8 +3806,19 @@ func_exit:
|
|||
page_rec_get_nth(merge_block->frame, nth_rec),
|
||||
merge_block, cursor);
|
||||
}
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
return(TRUE);
|
||||
err_exit:
|
||||
/* We play it safe and reset the free bits. */
|
||||
if (zip_size
|
||||
&& merge_page
|
||||
&& page_is_leaf(merge_page)
|
||||
&& !dict_index_is_clust(index)) {
|
||||
ibuf_reset_free_bits(merge_block);
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************//**
|
||||
|
|
@ -3816,18 +3880,17 @@ btr_discard_only_page_on_level(
|
|||
#endif /* UNIV_BTR_DEBUG */
|
||||
|
||||
btr_page_empty(block, buf_block_get_page_zip(block), index, 0, mtr);
|
||||
ut_ad(page_is_leaf(buf_block_get_frame(block)));
|
||||
|
||||
if (!dict_index_is_clust(index)) {
|
||||
/* We play it safe and reset the free bits for the root */
|
||||
ibuf_reset_free_bits(block);
|
||||
|
||||
if (page_is_leaf(buf_block_get_frame(block))) {
|
||||
ut_a(max_trx_id);
|
||||
page_set_max_trx_id(block,
|
||||
buf_block_get_page_zip(block),
|
||||
max_trx_id, mtr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*************************************************************//**
|
||||
|
|
@ -4489,9 +4552,9 @@ loop:
|
|||
right_page_no = btr_page_get_next(page, &mtr);
|
||||
left_page_no = btr_page_get_prev(page, &mtr);
|
||||
|
||||
ut_a(page_get_n_recs(page) > 0 || (level == 0
|
||||
&& page_get_page_no(page)
|
||||
== dict_index_get_page(index)));
|
||||
ut_a(!page_is_empty(page)
|
||||
|| (level == 0
|
||||
&& page_get_page_no(page) == dict_index_get_page(index)));
|
||||
|
||||
if (right_page_no != FIL_NULL) {
|
||||
const rec_t* right_rec;
|
||||
|
|
@ -4799,4 +4862,97 @@ btr_validate_index(
|
|||
return(ok);
|
||||
}
|
||||
|
||||
/**************************************************************//**
|
||||
Checks if the page in the cursor can be merged with given page.
|
||||
If necessary, re-organize the merge_page.
|
||||
@return TRUE if possible to merge. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
btr_can_merge_with_page(
|
||||
/*====================*/
|
||||
btr_cur_t* cursor, /*!< in: cursor on the page to merge */
|
||||
ulint page_no, /*!< in: a sibling page */
|
||||
buf_block_t** merge_block, /*!< out: the merge block */
|
||||
mtr_t* mtr) /*!< in: mini-transaction */
|
||||
{
|
||||
dict_index_t* index;
|
||||
page_t* page;
|
||||
ulint space;
|
||||
ulint zip_size;
|
||||
ulint n_recs;
|
||||
ulint data_size;
|
||||
ulint max_ins_size_reorg;
|
||||
ulint max_ins_size;
|
||||
buf_block_t* mblock;
|
||||
page_t* mpage;
|
||||
DBUG_ENTER("btr_can_merge_with_page");
|
||||
|
||||
if (page_no == FIL_NULL) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
index = btr_cur_get_index(cursor);
|
||||
page = btr_cur_get_page(cursor);
|
||||
space = dict_index_get_space(index);
|
||||
zip_size = dict_table_zip_size(index->table);
|
||||
|
||||
mblock = btr_block_get(space, zip_size, page_no, RW_X_LATCH, index,
|
||||
mtr);
|
||||
mpage = buf_block_get_frame(mblock);
|
||||
|
||||
n_recs = page_get_n_recs(page);
|
||||
data_size = page_get_data_size(page);
|
||||
|
||||
max_ins_size_reorg = page_get_max_insert_size_after_reorganize(
|
||||
mpage, n_recs);
|
||||
|
||||
if (data_size > max_ins_size_reorg) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* If compression padding tells us that merging will result in
|
||||
too packed up page i.e.: which is likely to cause compression
|
||||
failure then don't merge the pages. */
|
||||
if (zip_size && page_is_leaf(mpage)
|
||||
&& (page_get_data_size(mpage) + data_size
|
||||
>= dict_index_zip_pad_optimal_page_size(index))) {
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
|
||||
max_ins_size = page_get_max_insert_size(mpage, n_recs);
|
||||
|
||||
if (data_size > max_ins_size) {
|
||||
|
||||
/* We have to reorganize mpage */
|
||||
|
||||
if (!btr_page_reorganize_block(
|
||||
false, page_zip_level, mblock, index, mtr)) {
|
||||
|
||||
goto error;
|
||||
}
|
||||
|
||||
max_ins_size = page_get_max_insert_size(mpage, n_recs);
|
||||
|
||||
ut_ad(page_validate(mpage, index));
|
||||
ut_ad(max_ins_size == max_ins_size_reorg);
|
||||
|
||||
if (data_size > max_ins_size) {
|
||||
|
||||
/* Add fault tolerance, though this should
|
||||
never happen */
|
||||
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
|
||||
*merge_block = mblock;
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
error:
|
||||
*merge_block = NULL;
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -126,7 +126,7 @@ btr_pcur_store_position(
|
|||
|| mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
|
||||
if (page_is_empty(page)) {
|
||||
/* It must be an empty index tree; NOTE that in this case
|
||||
we do not store the modify_clock, but always do a search
|
||||
if we restore the cursor position */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2006, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2006, 2013, 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
|
||||
|
|
@ -33,12 +33,128 @@ Created December 2006 by Marko Makela
|
|||
#include "buf0lru.h"
|
||||
#include "buf0flu.h"
|
||||
#include "page0zip.h"
|
||||
#include "srv0start.h"
|
||||
|
||||
/** When freeing a buf we attempt to coalesce by looking at its buddy
|
||||
and deciding whether it is free or not. To ascertain if the buddy is
|
||||
free we look for BUF_BUDDY_STAMP_FREE at BUF_BUDDY_STAMP_OFFSET
|
||||
within the buddy. The question is how we can be sure that it is
|
||||
safe to look at BUF_BUDDY_STAMP_OFFSET.
|
||||
The answer lies in following invariants:
|
||||
* All blocks allocated by buddy allocator are used for compressed
|
||||
page frame.
|
||||
* A compressed table always have space_id < SRV_LOG_SPACE_FIRST_ID
|
||||
* BUF_BUDDY_STAMP_OFFSET always points to the space_id field in
|
||||
a frame.
|
||||
-- The above is true because we look at these fields when the
|
||||
corresponding buddy block is free which implies that:
|
||||
* The block we are looking at must have an address aligned at
|
||||
the same size that its free buddy has. For example, if we have
|
||||
a free block of 8K then its buddy's address must be aligned at
|
||||
8K as well.
|
||||
* It is possible that the block we are looking at may have been
|
||||
further divided into smaller sized blocks but its starting
|
||||
address must still remain the start of a page frame i.e.: it
|
||||
cannot be middle of a block. For example, if we have a free
|
||||
block of size 8K then its buddy may be divided into blocks
|
||||
of, say, 1K, 1K, 2K, 4K but the buddy's address will still be
|
||||
the starting address of first 1K compressed page.
|
||||
* What is important to note is that for any given block, the
|
||||
buddy's address cannot be in the middle of a larger block i.e.:
|
||||
in above example, our 8K block cannot have a buddy whose address
|
||||
is aligned on 8K but it is part of a larger 16K block.
|
||||
*/
|
||||
|
||||
/** Offset within buf_buddy_free_t where free or non_free stamps
|
||||
are written.*/
|
||||
#define BUF_BUDDY_STAMP_OFFSET FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID
|
||||
|
||||
/** Value that we stamp on all buffers that are currently on the zip_free
|
||||
list. This value is stamped at BUF_BUDDY_STAMP_OFFSET offset */
|
||||
#define BUF_BUDDY_STAMP_FREE (SRV_LOG_SPACE_FIRST_ID)
|
||||
|
||||
/** Stamp value for non-free buffers. Will be overwritten by a non-zero
|
||||
value by the consumer of the block */
|
||||
#define BUF_BUDDY_STAMP_NONFREE (0XFFFFFFFF)
|
||||
|
||||
#if BUF_BUDDY_STAMP_FREE >= BUF_BUDDY_STAMP_NONFREE
|
||||
# error "BUF_BUDDY_STAMP_FREE >= BUF_BUDDY_STAMP_NONFREE"
|
||||
#endif
|
||||
|
||||
/** Return type of buf_buddy_is_free() */
|
||||
enum buf_buddy_state_t {
|
||||
BUF_BUDDY_STATE_FREE, /*!< If the buddy to completely free */
|
||||
BUF_BUDDY_STATE_USED, /*!< Buddy currently in used */
|
||||
BUF_BUDDY_STATE_PARTIALLY_USED/*!< Some sub-blocks in the buddy
|
||||
are in use */
|
||||
};
|
||||
|
||||
#ifdef UNIV_DEBUG_VALGRIND
|
||||
/**********************************************************************//**
|
||||
Invalidate memory area that we won't access while page is free */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_buddy_mem_invalid(
|
||||
/*==================*/
|
||||
buf_buddy_free_t* buf, /*!< in: block to check */
|
||||
ulint i) /*!< in: index of zip_free[] */
|
||||
{
|
||||
const size_t size = BUF_BUDDY_LOW << i;
|
||||
ut_ad(i <= BUF_BUDDY_SIZES);
|
||||
|
||||
UNIV_MEM_ASSERT_W(buf, size);
|
||||
UNIV_MEM_INVALID(buf, size);
|
||||
}
|
||||
#else /* UNIV_DEBUG_VALGRIND */
|
||||
# define buf_buddy_mem_invalid(buf, i) ut_ad((i) <= BUF_BUDDY_SIZES)
|
||||
#endif /* UNIV_DEBUG_VALGRIND */
|
||||
|
||||
/**********************************************************************//**
|
||||
Check if a buddy is stamped free.
|
||||
@return whether the buddy is free */
|
||||
UNIV_INLINE __attribute__((warn_unused_result))
|
||||
bool
|
||||
buf_buddy_stamp_is_free(
|
||||
/*====================*/
|
||||
const buf_buddy_free_t* buf) /*!< in: block to check */
|
||||
{
|
||||
return(mach_read_from_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET)
|
||||
== BUF_BUDDY_STAMP_FREE);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Stamps a buddy free. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_buddy_stamp_free(
|
||||
/*=================*/
|
||||
buf_buddy_free_t* buf, /*!< in/out: block to stamp */
|
||||
ulint i) /*!< in: block size */
|
||||
{
|
||||
ut_d(memset(buf, i, BUF_BUDDY_LOW << i));
|
||||
buf_buddy_mem_invalid(buf, i);
|
||||
mach_write_to_4(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET,
|
||||
BUF_BUDDY_STAMP_FREE);
|
||||
buf->stamp.size = i;
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Stamps a buddy nonfree.
|
||||
@param[in/out] buf block to stamp
|
||||
@param[in] i block size */
|
||||
#define buf_buddy_stamp_nonfree(buf, i) do { \
|
||||
buf_buddy_mem_invalid(buf, i); \
|
||||
memset(buf->stamp.bytes + BUF_BUDDY_STAMP_OFFSET, 0xff, 4); \
|
||||
} while (0)
|
||||
#if BUF_BUDDY_STAMP_NONFREE != 0xffffffff
|
||||
# error "BUF_BUDDY_STAMP_NONFREE != 0xffffffff"
|
||||
#endif
|
||||
|
||||
/**********************************************************************//**
|
||||
Get the offset of the buddy of a compressed page frame.
|
||||
@return the buddy relative of page */
|
||||
UNIV_INLINE
|
||||
byte*
|
||||
void*
|
||||
buf_buddy_get(
|
||||
/*==========*/
|
||||
byte* page, /*!< in: compressed page */
|
||||
|
|
@ -60,14 +176,96 @@ buf_buddy_get(
|
|||
|
||||
/** Validate a given zip_free list. */
|
||||
struct CheckZipFree {
|
||||
void operator()(const buf_page_t* elem) const
|
||||
ulint i;
|
||||
CheckZipFree(ulint i) : i (i) {}
|
||||
|
||||
void operator()(const buf_buddy_free_t* elem) const
|
||||
{
|
||||
ut_a(buf_page_get_state(elem) == BUF_BLOCK_ZIP_FREE);
|
||||
ut_a(buf_buddy_stamp_is_free(elem));
|
||||
ut_a(elem->stamp.size <= i);
|
||||
}
|
||||
};
|
||||
|
||||
#define BUF_BUDDY_LIST_VALIDATE(bp, i) \
|
||||
UT_LIST_VALIDATE(list, buf_page_t, bp->zip_free[i], CheckZipFree())
|
||||
UT_LIST_VALIDATE(list, buf_buddy_free_t, \
|
||||
bp->zip_free[i], CheckZipFree(i))
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/**********************************************************************//**
|
||||
Debug function to validate that a buffer is indeed free i.e.: in the
|
||||
zip_free[].
|
||||
@return true if free */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
buf_buddy_check_free(
|
||||
/*=================*/
|
||||
buf_pool_t* buf_pool,/*!< in: buffer pool instance */
|
||||
const buf_buddy_free_t* buf, /*!< in: block to check */
|
||||
ulint i) /*!< in: index of buf_pool->zip_free[] */
|
||||
{
|
||||
const ulint size = BUF_BUDDY_LOW << i;
|
||||
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_ad(!ut_align_offset(buf, size));
|
||||
ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
|
||||
|
||||
buf_buddy_free_t* itr;
|
||||
|
||||
for (itr = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
itr && itr != buf;
|
||||
itr = UT_LIST_GET_NEXT(list, itr)) {
|
||||
}
|
||||
|
||||
return(itr == buf);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/**********************************************************************//**
|
||||
Checks if a buf is free i.e.: in the zip_free[].
|
||||
@retval BUF_BUDDY_STATE_FREE if fully free
|
||||
@retval BUF_BUDDY_STATE_USED if currently in use
|
||||
@retval BUF_BUDDY_STATE_PARTIALLY_USED if partially in use. */
|
||||
static __attribute__((warn_unused_result))
|
||||
buf_buddy_state_t
|
||||
buf_buddy_is_free(
|
||||
/*==============*/
|
||||
buf_buddy_free_t* buf, /*!< in: block to check */
|
||||
ulint i) /*!< in: index of
|
||||
buf_pool->zip_free[] */
|
||||
{
|
||||
#ifdef UNIV_DEBUG
|
||||
const ulint size = BUF_BUDDY_LOW << i;
|
||||
ut_ad(!ut_align_offset(buf, size));
|
||||
ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/* We assume that all memory from buf_buddy_alloc()
|
||||
is used for compressed page frames. */
|
||||
|
||||
/* We look inside the allocated objects returned by
|
||||
buf_buddy_alloc() and assume that each block is a compressed
|
||||
page that contains one of the following in space_id.
|
||||
* BUF_BUDDY_STAMP_FREE if the block is in a zip_free list or
|
||||
* BUF_BUDDY_STAMP_NONFREE if the block has been allocated but
|
||||
not initialized yet or
|
||||
* A valid space_id of a compressed tablespace
|
||||
|
||||
The call below attempts to read from free memory. The memory
|
||||
is "owned" by the buddy allocator (and it has been allocated
|
||||
from the buffer pool), so there is nothing wrong about this. */
|
||||
if (!buf_buddy_stamp_is_free(buf)) {
|
||||
return(BUF_BUDDY_STATE_USED);
|
||||
}
|
||||
|
||||
/* A block may be free but a fragment of it may still be in use.
|
||||
To guard against that we write the free block size in terms of
|
||||
zip_free index at start of stamped block. Note that we can
|
||||
safely rely on this value only if the buf is free. */
|
||||
ut_ad(buf->stamp.size <= i);
|
||||
return(buf->stamp.size == i
|
||||
? BUF_BUDDY_STATE_FREE
|
||||
: BUF_BUDDY_STATE_PARTIALLY_USED);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Add a block to the head of the appropriate buddy free list. */
|
||||
|
|
@ -76,14 +274,16 @@ void
|
|||
buf_buddy_add_to_free(
|
||||
/*==================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
buf_page_t* bpage, /*!< in,own: block to be freed */
|
||||
buf_buddy_free_t* buf, /*!< in,own: block to be freed */
|
||||
ulint i) /*!< in: index of
|
||||
buf_pool->zip_free[] */
|
||||
{
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
|
||||
ut_ad(buf_pool->zip_free[i].start != bpage);
|
||||
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], bpage);
|
||||
ut_ad(buf_pool->zip_free[i].start != buf);
|
||||
|
||||
buf_buddy_stamp_free(buf, i);
|
||||
UT_LIST_ADD_FIRST(list, buf_pool->zip_free[i], buf);
|
||||
ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i));
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
@ -93,34 +293,28 @@ void
|
|||
buf_buddy_remove_from_free(
|
||||
/*=======================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
buf_page_t* bpage, /*!< in: block to be removed */
|
||||
buf_buddy_free_t* buf, /*!< in,own: block to be freed */
|
||||
ulint i) /*!< in: index of
|
||||
buf_pool->zip_free[] */
|
||||
{
|
||||
#ifdef UNIV_DEBUG
|
||||
buf_page_t* prev = UT_LIST_GET_PREV(list, bpage);
|
||||
buf_page_t* next = UT_LIST_GET_NEXT(list, bpage);
|
||||
|
||||
ut_ad(!prev || buf_page_get_state(prev) == BUF_BLOCK_ZIP_FREE);
|
||||
ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE);
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
|
||||
UT_LIST_REMOVE(list, buf_pool->zip_free[i], bpage);
|
||||
ut_ad(buf_buddy_check_free(buf_pool, buf, i));
|
||||
|
||||
UT_LIST_REMOVE(list, buf_pool->zip_free[i], buf);
|
||||
buf_buddy_stamp_nonfree(buf, i);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Try to allocate a block from buf_pool->zip_free[].
|
||||
@return allocated block, or NULL if buf_pool->zip_free[] was empty */
|
||||
static
|
||||
void*
|
||||
buf_buddy_free_t*
|
||||
buf_buddy_alloc_zip(
|
||||
/*================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
ulint i) /*!< in: index of buf_pool->zip_free[] */
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
buf_buddy_free_t* buf;
|
||||
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_a(i < BUF_BUDDY_SIZES);
|
||||
|
|
@ -128,33 +322,38 @@ buf_buddy_alloc_zip(
|
|||
|
||||
ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i));
|
||||
|
||||
bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
buf = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
|
||||
if (bpage) {
|
||||
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
|
||||
|
||||
buf_buddy_remove_from_free(buf_pool, bpage, i);
|
||||
if (buf) {
|
||||
buf_buddy_remove_from_free(buf_pool, buf, i);
|
||||
} else if (i + 1 < BUF_BUDDY_SIZES) {
|
||||
/* Attempt to split. */
|
||||
bpage = (buf_page_t*) buf_buddy_alloc_zip(buf_pool, i + 1);
|
||||
buf = buf_buddy_alloc_zip(buf_pool, i + 1);
|
||||
|
||||
if (bpage) {
|
||||
buf_page_t* buddy = (buf_page_t*)
|
||||
(((char*) bpage) + (BUF_BUDDY_LOW << i));
|
||||
if (buf) {
|
||||
buf_buddy_free_t* buddy =
|
||||
reinterpret_cast<buf_buddy_free_t*>(
|
||||
buf->stamp.bytes
|
||||
+ (BUF_BUDDY_LOW << i));
|
||||
|
||||
ut_ad(!buf_pool_contains_zip(buf_pool, buddy));
|
||||
ut_d(memset(buddy, i, BUF_BUDDY_LOW << i));
|
||||
buddy->state = BUF_BLOCK_ZIP_FREE;
|
||||
buf_buddy_add_to_free(buf_pool, buddy, i);
|
||||
}
|
||||
}
|
||||
|
||||
if (bpage) {
|
||||
ut_d(memset(bpage, ~i, BUF_BUDDY_LOW << i));
|
||||
UNIV_MEM_ALLOC(bpage, BUF_BUDDY_SIZES << i);
|
||||
if (buf) {
|
||||
/* Trash the page other than the BUF_BUDDY_STAMP_NONFREE. */
|
||||
UNIV_MEM_TRASH(buf, ~i, BUF_BUDDY_STAMP_OFFSET);
|
||||
UNIV_MEM_TRASH(BUF_BUDDY_STAMP_OFFSET + 4
|
||||
+ buf->stamp.bytes, ~i,
|
||||
(BUF_BUDDY_LOW << i)
|
||||
- (BUF_BUDDY_STAMP_OFFSET + 4));
|
||||
ut_ad(mach_read_from_4(buf->stamp.bytes
|
||||
+ BUF_BUDDY_STAMP_OFFSET)
|
||||
== BUF_BUDDY_STAMP_NONFREE);
|
||||
}
|
||||
|
||||
return(bpage);
|
||||
return(buf);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
@ -246,18 +445,17 @@ buf_buddy_alloc_from(
|
|||
|
||||
/* Add the unused parts of the block to the free lists. */
|
||||
while (j > i) {
|
||||
buf_page_t* bpage;
|
||||
buf_buddy_free_t* zip_buf;
|
||||
|
||||
offs >>= 1;
|
||||
j--;
|
||||
|
||||
bpage = (buf_page_t*) ((byte*) buf + offs);
|
||||
ut_d(memset(bpage, j, BUF_BUDDY_LOW << j));
|
||||
bpage->state = BUF_BLOCK_ZIP_FREE;
|
||||
ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i));
|
||||
buf_buddy_add_to_free(buf_pool, bpage, j);
|
||||
zip_buf = reinterpret_cast<buf_buddy_free_t*>(
|
||||
reinterpret_cast<byte*>(buf) + offs);
|
||||
buf_buddy_add_to_free(buf_pool, zip_buf, j);
|
||||
}
|
||||
|
||||
buf_buddy_stamp_nonfree(reinterpret_cast<buf_buddy_free_t*>(buf), i);
|
||||
return(buf);
|
||||
}
|
||||
|
||||
|
|
@ -322,9 +520,9 @@ func_exit:
|
|||
|
||||
/**********************************************************************//**
|
||||
Try to relocate a block.
|
||||
@return TRUE if relocated */
|
||||
@return true if relocated */
|
||||
static
|
||||
ibool
|
||||
bool
|
||||
buf_buddy_relocate(
|
||||
/*===============*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
|
|
@ -337,7 +535,7 @@ buf_buddy_relocate(
|
|||
const ulint size = BUF_BUDDY_LOW << i;
|
||||
ib_mutex_t* mutex;
|
||||
ulint space;
|
||||
ulint page_no;
|
||||
ulint offset;
|
||||
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_ad(!mutex_own(&buf_pool->zip_mutex));
|
||||
|
|
@ -346,32 +544,19 @@ buf_buddy_relocate(
|
|||
ut_ad(i >= buf_buddy_get_slot(UNIV_ZIP_SIZE_MIN));
|
||||
UNIV_MEM_ASSERT_W(dst, size);
|
||||
|
||||
/* We assume that all memory from buf_buddy_alloc()
|
||||
is used for compressed page frames. */
|
||||
|
||||
/* We look inside the allocated objects returned by
|
||||
buf_buddy_alloc() and assume that each block is a compressed
|
||||
page that contains a valid space_id and page_no in the page
|
||||
header. Should the fields be invalid, we will be unable to
|
||||
relocate the block. */
|
||||
|
||||
/* The src block may be split into smaller blocks,
|
||||
some of which may be free. Thus, the
|
||||
mach_read_from_4() calls below may attempt to read
|
||||
from free memory. The memory is "owned" by the buddy
|
||||
allocator (and it has been allocated from the buffer
|
||||
pool), so there is nothing wrong about this. The
|
||||
mach_read_from_4() calls here will only trigger bogus
|
||||
Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
|
||||
space = mach_read_from_4((const byte*) src
|
||||
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
|
||||
page_no = mach_read_from_4((const byte*) src
|
||||
offset = mach_read_from_4((const byte*) src
|
||||
+ FIL_PAGE_OFFSET);
|
||||
|
||||
/* Suppress Valgrind warnings about conditional jump
|
||||
on uninitialized value. */
|
||||
UNIV_MEM_VALID(&space, sizeof space);
|
||||
UNIV_MEM_VALID(&page_no, sizeof page_no);
|
||||
bpage = buf_page_hash_get(buf_pool, space, page_no);
|
||||
UNIV_MEM_VALID(&offset, sizeof offset);
|
||||
|
||||
ut_ad(space != BUF_BUDDY_STAMP_FREE);
|
||||
|
||||
bpage = buf_page_hash_get(buf_pool, space, offset);
|
||||
|
||||
if (!bpage || bpage->zip.data != src) {
|
||||
/* The block has probably been freshly
|
||||
|
|
@ -379,7 +564,7 @@ buf_buddy_relocate(
|
|||
added to buf_pool->page_hash yet. Obviously,
|
||||
it cannot be relocated. */
|
||||
|
||||
return(FALSE);
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (page_zip_get_size(&bpage->zip) != size) {
|
||||
|
|
@ -388,7 +573,7 @@ buf_buddy_relocate(
|
|||
For the sake of simplicity, give up. */
|
||||
ut_ad(page_zip_get_size(&bpage->zip) < size);
|
||||
|
||||
return(FALSE);
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* The block must have been allocated, but it may
|
||||
|
|
@ -406,19 +591,17 @@ buf_buddy_relocate(
|
|||
memcpy(dst, src, size);
|
||||
bpage->zip.data = (page_zip_t*) dst;
|
||||
mutex_exit(mutex);
|
||||
UNIV_MEM_INVALID(src, size);
|
||||
{
|
||||
buf_buddy_stat_t* buddy_stat
|
||||
= &buf_pool->buddy_stat[i];
|
||||
buf_buddy_mem_invalid(
|
||||
reinterpret_cast<buf_buddy_free_t*>(src), i);
|
||||
|
||||
buf_buddy_stat_t* buddy_stat = &buf_pool->buddy_stat[i];
|
||||
buddy_stat->relocated++;
|
||||
buddy_stat->relocated_usec
|
||||
+= ut_time_us(NULL) - usec;
|
||||
}
|
||||
return(TRUE);
|
||||
buddy_stat->relocated_usec += ut_time_us(NULL) - usec;
|
||||
return(true);
|
||||
}
|
||||
|
||||
mutex_exit(mutex);
|
||||
return(FALSE);
|
||||
return(false);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
@ -433,8 +616,7 @@ buf_buddy_free_low(
|
|||
ulint i) /*!< in: index of buf_pool->zip_free[],
|
||||
or BUF_BUDDY_SIZES */
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
buf_page_t* buddy;
|
||||
buf_buddy_free_t* buddy;
|
||||
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_ad(!mutex_own(&buf_pool->zip_mutex));
|
||||
|
|
@ -445,7 +627,6 @@ buf_buddy_free_low(
|
|||
buf_pool->buddy_stat[i].used--;
|
||||
recombine:
|
||||
UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i);
|
||||
((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE;
|
||||
|
||||
if (i == BUF_BUDDY_SIZES) {
|
||||
buf_buddy_block_free(buf_pool, buf);
|
||||
|
|
@ -464,73 +645,54 @@ recombine:
|
|||
}
|
||||
|
||||
/* Try to combine adjacent blocks. */
|
||||
buddy = (buf_page_t*) buf_buddy_get(((byte*) buf), BUF_BUDDY_LOW << i);
|
||||
buddy = reinterpret_cast<buf_buddy_free_t*>(
|
||||
buf_buddy_get(reinterpret_cast<byte*>(buf),
|
||||
BUF_BUDDY_LOW << i));
|
||||
|
||||
#ifndef UNIV_DEBUG_VALGRIND
|
||||
/* When Valgrind instrumentation is not enabled, we can read
|
||||
buddy->state to quickly determine that a block is not free.
|
||||
When the block is not free, buddy->state belongs to a compressed
|
||||
page frame that may be flagged uninitialized in our Valgrind
|
||||
instrumentation. */
|
||||
|
||||
if (buddy->state != BUF_BLOCK_ZIP_FREE) {
|
||||
|
||||
goto buddy_nonfree;
|
||||
}
|
||||
#endif /* !UNIV_DEBUG_VALGRIND */
|
||||
|
||||
for (bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); bpage; ) {
|
||||
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
|
||||
|
||||
if (bpage == buddy) {
|
||||
switch (buf_buddy_is_free(buddy, i)) {
|
||||
case BUF_BUDDY_STATE_FREE:
|
||||
/* The buddy is free: recombine */
|
||||
buf_buddy_remove_from_free(buf_pool, bpage, i);
|
||||
buf_buddy_remove_from_free(buf_pool, buddy, i);
|
||||
buddy_is_free:
|
||||
ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE);
|
||||
ut_ad(!buf_pool_contains_zip(buf_pool, buddy));
|
||||
i++;
|
||||
buf = ut_align_down(buf, BUF_BUDDY_LOW << i);
|
||||
|
||||
goto recombine;
|
||||
}
|
||||
|
||||
ut_a(bpage != buf);
|
||||
UNIV_MEM_ASSERT_W(bpage, BUF_BUDDY_LOW << i);
|
||||
bpage = UT_LIST_GET_NEXT(list, bpage);
|
||||
}
|
||||
|
||||
#ifndef UNIV_DEBUG_VALGRIND
|
||||
buddy_nonfree:
|
||||
#endif /* !UNIV_DEBUG_VALGRIND */
|
||||
|
||||
case BUF_BUDDY_STATE_USED:
|
||||
ut_d(BUF_BUDDY_LIST_VALIDATE(buf_pool, i));
|
||||
|
||||
/* The buddy is not free. Is there a free block of this size? */
|
||||
bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
/* The buddy is not free. Is there a free block of
|
||||
this size? */
|
||||
if (buf_buddy_free_t* zip_buf =
|
||||
UT_LIST_GET_FIRST(buf_pool->zip_free[i])) {
|
||||
|
||||
if (bpage) {
|
||||
/* Remove the block from the free list, because
|
||||
a successful buf_buddy_relocate() will overwrite
|
||||
zip_free->list. */
|
||||
buf_buddy_remove_from_free(buf_pool, zip_buf, i);
|
||||
|
||||
/* Remove the block from the free list, because a successful
|
||||
buf_buddy_relocate() will overwrite bpage->list. */
|
||||
buf_buddy_remove_from_free(buf_pool, bpage, i);
|
||||
/* Try to relocate the buddy of buf to the free
|
||||
block. */
|
||||
if (buf_buddy_relocate(buf_pool, buddy, zip_buf, i)) {
|
||||
|
||||
/* Try to relocate the buddy of buf to the free block. */
|
||||
if (buf_buddy_relocate(buf_pool, buddy, bpage, i)) {
|
||||
|
||||
buddy->state = BUF_BLOCK_ZIP_FREE;
|
||||
goto buddy_is_free;
|
||||
}
|
||||
|
||||
buf_buddy_add_to_free(buf_pool, bpage, i);
|
||||
buf_buddy_add_to_free(buf_pool, zip_buf, i);
|
||||
}
|
||||
|
||||
break;
|
||||
case BUF_BUDDY_STATE_PARTIALLY_USED:
|
||||
/* Some sub-blocks in the buddy are still in use.
|
||||
Relocation will fail. No need to try. */
|
||||
break;
|
||||
}
|
||||
|
||||
func_exit:
|
||||
/* Free the block to the buddy list. */
|
||||
bpage = (buf_page_t*) buf;
|
||||
|
||||
/* Fill large blocks with a constant pattern. */
|
||||
ut_d(memset(bpage, i, BUF_BUDDY_LOW << i));
|
||||
UNIV_MEM_INVALID(bpage, BUF_BUDDY_LOW << i);
|
||||
bpage->state = BUF_BLOCK_ZIP_FREE;
|
||||
buf_buddy_add_to_free(buf_pool, bpage, i);
|
||||
buf_buddy_add_to_free(buf_pool,
|
||||
reinterpret_cast<buf_buddy_free_t*>(buf),
|
||||
i);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
|
|
@ -496,14 +496,13 @@ buf_page_is_corrupted(
|
|||
}
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
if (recv_lsn_checks_on) {
|
||||
if (check_lsn && recv_lsn_checks_on) {
|
||||
lsn_t current_lsn;
|
||||
|
||||
/* Since we are going to reset the page LSN during the import
|
||||
phase it makes no sense to spam the log with error messages. */
|
||||
|
||||
if (check_lsn
|
||||
&& log_peek_lsn(¤t_lsn)
|
||||
if (log_peek_lsn(¤t_lsn)
|
||||
&& current_lsn
|
||||
< mach_read_from_8(read_buf + FIL_PAGE_LSN)) {
|
||||
ut_print_timestamp(stderr);
|
||||
|
|
@ -1167,7 +1166,7 @@ buf_chunk_not_freed(
|
|||
ibool ready;
|
||||
|
||||
switch (buf_block_get_state(block)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
/* The uncompressed buffer pool should never
|
||||
|
|
@ -1492,7 +1491,7 @@ buf_relocate(
|
|||
ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
|
||||
#ifdef UNIV_DEBUG
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
|
|
@ -1964,7 +1963,7 @@ buf_block_try_discard_uncompressed(
|
|||
bpage = buf_page_hash_get(buf_pool, space, offset);
|
||||
|
||||
if (bpage) {
|
||||
buf_LRU_free_block(bpage, FALSE);
|
||||
buf_LRU_free_page(bpage, false);
|
||||
}
|
||||
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
|
|
@ -2014,7 +2013,7 @@ lookup:
|
|||
buf_read_page(space, zip_size, offset);
|
||||
|
||||
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
||||
ut_a(++buf_dbg_counter % 37 || buf_validate());
|
||||
ut_a(++buf_dbg_counter % 5771 || buf_validate());
|
||||
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
||||
}
|
||||
|
||||
|
|
@ -2030,11 +2029,11 @@ err_exit:
|
|||
ut_ad(!buf_pool_watch_is_sentinel(buf_pool, bpage));
|
||||
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
case BUF_BLOCK_REMOVE_HASH:
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
break;
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
|
|
@ -2240,7 +2239,7 @@ buf_block_align_instance(
|
|||
mutex_enter(&block->mutex);
|
||||
|
||||
switch (buf_block_get_state(block)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
/* These types should only be used in
|
||||
|
|
@ -2436,7 +2435,6 @@ buf_page_get_gen(
|
|||
ibool must_read;
|
||||
rw_lock_t* hash_lock;
|
||||
ib_mutex_t* block_mutex;
|
||||
buf_page_t* hash_bpage;
|
||||
ulint retries = 0;
|
||||
buf_pool_t* buf_pool = buf_pool_get(space, offset);
|
||||
|
||||
|
|
@ -2489,7 +2487,6 @@ loop:
|
|||
block = guess = NULL;
|
||||
} else {
|
||||
ut_ad(!block->page.in_zip_hash);
|
||||
ut_ad(block->page.in_page_hash);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2543,6 +2540,10 @@ loop:
|
|||
retries = 0;
|
||||
} else if (retries < BUF_PAGE_READ_MAX_RETRIES) {
|
||||
++retries;
|
||||
DBUG_EXECUTE_IF(
|
||||
"innodb_page_corruption_retries",
|
||||
retries = BUF_PAGE_READ_MAX_RETRIES;
|
||||
);
|
||||
} else {
|
||||
fprintf(stderr, "InnoDB: Error: Unable"
|
||||
" to read tablespace %lu page no"
|
||||
|
|
@ -2564,7 +2565,7 @@ loop:
|
|||
}
|
||||
|
||||
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
||||
ut_a(++buf_dbg_counter % 37 || buf_validate());
|
||||
ut_a(++buf_dbg_counter % 5771 || buf_validate());
|
||||
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
||||
goto loop;
|
||||
}
|
||||
|
|
@ -2590,6 +2591,7 @@ got_block:
|
|||
/* The page is being read to buffer pool,
|
||||
but we cannot wait around for the read to
|
||||
complete. */
|
||||
null_exit:
|
||||
mutex_exit(block_mutex);
|
||||
|
||||
return(NULL);
|
||||
|
|
@ -2603,6 +2605,14 @@ got_block:
|
|||
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
if (mode == BUF_PEEK_IF_IN_POOL) {
|
||||
/* This mode is only used for dropping an
|
||||
adaptive hash index. There cannot be an
|
||||
adaptive hash index for a compressed-only
|
||||
page, so do not bother decompressing the page. */
|
||||
goto null_exit;
|
||||
}
|
||||
|
||||
bpage = &block->page;
|
||||
|
||||
if (bpage->buf_fix_count
|
||||
|
|
@ -2735,7 +2745,7 @@ wait_until_unfixed:
|
|||
|
||||
break;
|
||||
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
|
|
@ -2780,7 +2790,7 @@ wait_until_unfixed:
|
|||
relocated or enter or exit the buf_pool while we
|
||||
are holding the buf_pool->mutex. */
|
||||
|
||||
if (buf_LRU_free_block(&block->page, TRUE)) {
|
||||
if (buf_LRU_free_page(&block->page, true)) {
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
rw_lock_x_lock(hash_lock);
|
||||
|
||||
|
|
@ -3728,7 +3738,7 @@ buf_page_create(
|
|||
memset(frame + FIL_PAGE_FILE_FLUSH_LSN, 0, 8);
|
||||
|
||||
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
||||
ut_a(++buf_dbg_counter % 357 || buf_validate());
|
||||
ut_a(++buf_dbg_counter % 5771 || buf_validate());
|
||||
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
||||
#ifdef UNIV_IBUF_COUNT_DEBUG
|
||||
ut_a(ibuf_count_get(buf_block_get_space(block),
|
||||
|
|
@ -4196,7 +4206,7 @@ buf_pool_invalidate_instance(
|
|||
pool invalidation to proceed we must ensure there is NO
|
||||
write activity happening. */
|
||||
if (buf_pool->n_flush[i] > 0) {
|
||||
enum buf_flush type = static_cast<enum buf_flush>(i);
|
||||
buf_flush_t type = static_cast<buf_flush_t>(i);
|
||||
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
buf_flush_wait_batch_end(buf_pool, type);
|
||||
|
|
@ -4285,7 +4295,7 @@ buf_pool_validate_instance(
|
|||
mutex_enter(&block->mutex);
|
||||
|
||||
switch (buf_block_get_state(block)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
/* These should only occur on
|
||||
|
|
@ -4378,7 +4388,7 @@ assert_s_latched:
|
|||
/* All clean blocks should be I/O-unfixed. */
|
||||
break;
|
||||
case BUF_IO_READ:
|
||||
/* In buf_LRU_free_block(), we temporarily set
|
||||
/* In buf_LRU_free_page(), we temporarily set
|
||||
b->io_fix = BUF_IO_READ for a newly allocated
|
||||
control block in order to prevent
|
||||
buf_page_get_gen() from decompressing the block. */
|
||||
|
|
@ -4437,7 +4447,7 @@ assert_s_latched:
|
|||
case BUF_BLOCK_FILE_PAGE:
|
||||
/* uncompressed page */
|
||||
break;
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
|
|
@ -4720,7 +4730,7 @@ buf_get_latched_pages_number_instance(
|
|||
case BUF_BLOCK_FILE_PAGE:
|
||||
/* uncompressed page */
|
||||
break;
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
|
|
@ -5015,7 +5025,7 @@ buf_print_io_instance(
|
|||
"Old database pages %lu\n"
|
||||
"Modified db pages %lu\n"
|
||||
"Pending reads %lu\n"
|
||||
"Pending writes: LRU %lu, flush list %lu single page %lu\n",
|
||||
"Pending writes: LRU %lu, flush list %lu, single page %lu\n",
|
||||
pool_info->pool_size,
|
||||
pool_info->free_list_len,
|
||||
pool_info->lru_len,
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -38,11 +38,6 @@ Created 2011/12/19
|
|||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
|
||||
/** Time in milliseconds that we sleep when unable to find a slot in
|
||||
the doublewrite buffer or when we have to wait for a running batch
|
||||
to end. */
|
||||
#define TRX_DOUBLEWRITE_BATCH_POLL_DELAY 10000
|
||||
|
||||
#ifdef UNIV_PFS_MUTEX
|
||||
/* Key to register the mutex with performance schema */
|
||||
UNIV_INTERN mysql_pfs_key_t buf_dblwr_mutex_key;
|
||||
|
|
@ -104,6 +99,25 @@ buf_dblwr_get(
|
|||
return(buf_block_get_frame(block) + TRX_SYS_DOUBLEWRITE);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Flush a batch of writes to the datafiles that have already been
|
||||
written to the dblwr buffer on disk. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_dblwr_sync_datafiles()
|
||||
/*======================*/
|
||||
{
|
||||
/* Wake possible simulated aio thread to actually post the
|
||||
writes to the operating system */
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
/* Wait that all async writes to tablespaces have been posted to
|
||||
the OS */
|
||||
os_aio_wait_until_no_pending_writes();
|
||||
|
||||
/* Now we flush the data to disk (for example, with fsync) */
|
||||
fil_flush_file_spaces(FIL_TABLESPACE);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Creates or initialializes the doublewrite buffer at a database start. */
|
||||
|
|
@ -131,6 +145,8 @@ buf_dblwr_init(
|
|||
mutex_create(buf_dblwr_mutex_key,
|
||||
&buf_dblwr->mutex, SYNC_DOUBLEWRITE);
|
||||
|
||||
buf_dblwr->b_event = os_event_create();
|
||||
buf_dblwr->s_event = os_event_create();
|
||||
buf_dblwr->first_free = 0;
|
||||
buf_dblwr->s_reserved = 0;
|
||||
buf_dblwr->b_reserved = 0;
|
||||
|
|
@ -140,8 +156,8 @@ buf_dblwr_init(
|
|||
buf_dblwr->block2 = mach_read_from_4(
|
||||
doublewrite + TRX_SYS_DOUBLEWRITE_BLOCK2);
|
||||
|
||||
buf_dblwr->in_use = static_cast<ibool*>(
|
||||
mem_zalloc(buf_size * sizeof(ibool)));
|
||||
buf_dblwr->in_use = static_cast<bool*>(
|
||||
mem_zalloc(buf_size * sizeof(bool)));
|
||||
|
||||
buf_dblwr->write_buf_unaligned = static_cast<byte*>(
|
||||
ut_malloc((1 + buf_size) * UNIV_PAGE_SIZE));
|
||||
|
|
@ -365,7 +381,7 @@ buf_dblwr_init_or_restore_pages(
|
|||
/* Read the trx sys header to check if we are using the doublewrite
|
||||
buffer */
|
||||
|
||||
fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, 0,
|
||||
fil_io(OS_FILE_READ, true, TRX_SYS_SPACE, 0, TRX_SYS_PAGE_NO, 0,
|
||||
UNIV_PAGE_SIZE, read_buf, NULL);
|
||||
doublewrite = read_buf + TRX_SYS_DOUBLEWRITE;
|
||||
|
||||
|
|
@ -400,10 +416,10 @@ buf_dblwr_init_or_restore_pages(
|
|||
|
||||
/* Read the pages from the doublewrite buffer to memory */
|
||||
|
||||
fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block1, 0,
|
||||
fil_io(OS_FILE_READ, true, TRX_SYS_SPACE, 0, block1, 0,
|
||||
TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
|
||||
buf, NULL);
|
||||
fil_io(OS_FILE_READ, TRUE, TRX_SYS_SPACE, 0, block2, 0,
|
||||
fil_io(OS_FILE_READ, true, TRX_SYS_SPACE, 0, block2, 0,
|
||||
TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
|
||||
buf + TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE,
|
||||
NULL);
|
||||
|
|
@ -433,7 +449,7 @@ buf_dblwr_init_or_restore_pages(
|
|||
+ i - TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
|
||||
}
|
||||
|
||||
fil_io(OS_FILE_WRITE, TRUE, 0, 0, source_page_no, 0,
|
||||
fil_io(OS_FILE_WRITE, true, 0, 0, source_page_no, 0,
|
||||
UNIV_PAGE_SIZE, page, NULL);
|
||||
} else {
|
||||
|
||||
|
|
@ -473,7 +489,7 @@ buf_dblwr_init_or_restore_pages(
|
|||
ulint zip_size = fil_space_get_zip_size(space_id);
|
||||
|
||||
/* Read in the actual page from the file */
|
||||
fil_io(OS_FILE_READ, TRUE, space_id, zip_size,
|
||||
fil_io(OS_FILE_READ, true, space_id, zip_size,
|
||||
page_no, 0,
|
||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
||||
read_buf, NULL);
|
||||
|
|
@ -525,7 +541,7 @@ buf_dblwr_init_or_restore_pages(
|
|||
doublewrite buffer to the intended
|
||||
position */
|
||||
|
||||
fil_io(OS_FILE_WRITE, TRUE, space_id,
|
||||
fil_io(OS_FILE_WRITE, true, space_id,
|
||||
zip_size, page_no, 0,
|
||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
||||
page, NULL);
|
||||
|
|
@ -557,6 +573,8 @@ buf_dblwr_free(void)
|
|||
ut_ad(buf_dblwr->s_reserved == 0);
|
||||
ut_ad(buf_dblwr->b_reserved == 0);
|
||||
|
||||
os_event_free(buf_dblwr->b_event);
|
||||
os_event_free(buf_dblwr->s_event);
|
||||
ut_free(buf_dblwr->write_buf_unaligned);
|
||||
buf_dblwr->write_buf_unaligned = NULL;
|
||||
|
||||
|
|
@ -572,17 +590,21 @@ buf_dblwr_free(void)
|
|||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Updates the doublewrite buffer when an IO request that is part of an
|
||||
LRU or flush batch is completed. */
|
||||
Updates the doublewrite buffer when an IO request is completed. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
buf_dblwr_update(void)
|
||||
/*==================*/
|
||||
buf_dblwr_update(
|
||||
/*=============*/
|
||||
const buf_page_t* bpage, /*!< in: buffer block descriptor */
|
||||
buf_flush_t flush_type)/*!< in: flush type */
|
||||
{
|
||||
if (!srv_use_doublewrite_buf || buf_dblwr == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (flush_type) {
|
||||
case BUF_FLUSH_LIST:
|
||||
case BUF_FLUSH_LRU:
|
||||
mutex_enter(&buf_dblwr->mutex);
|
||||
|
||||
ut_ad(buf_dblwr->batch_running);
|
||||
|
|
@ -590,8 +612,8 @@ buf_dblwr_update(void)
|
|||
ut_ad(buf_dblwr->b_reserved <= buf_dblwr->first_free);
|
||||
|
||||
buf_dblwr->b_reserved--;
|
||||
if (buf_dblwr->b_reserved == 0) {
|
||||
|
||||
if (buf_dblwr->b_reserved == 0) {
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
/* This will finish the batch. Sync data files
|
||||
to the disk. */
|
||||
|
|
@ -600,10 +622,36 @@ buf_dblwr_update(void)
|
|||
|
||||
/* We can now reuse the doublewrite memory buffer: */
|
||||
buf_dblwr->first_free = 0;
|
||||
buf_dblwr->batch_running = FALSE;
|
||||
buf_dblwr->batch_running = false;
|
||||
os_event_set(buf_dblwr->b_event);
|
||||
}
|
||||
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
break;
|
||||
case BUF_FLUSH_SINGLE_PAGE:
|
||||
{
|
||||
const ulint size = 2 * TRX_SYS_DOUBLEWRITE_BLOCK_SIZE;
|
||||
ulint i;
|
||||
mutex_enter(&buf_dblwr->mutex);
|
||||
for (i = srv_doublewrite_batch_size; i < size; ++i) {
|
||||
if (buf_dblwr->buf_block_arr[i] == bpage) {
|
||||
buf_dblwr->s_reserved--;
|
||||
buf_dblwr->buf_block_arr[i] = NULL;
|
||||
buf_dblwr->in_use[i] = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* The block we are looking for must exist as a
|
||||
reserved block. */
|
||||
ut_a(i < size);
|
||||
}
|
||||
os_event_set(buf_dblwr->s_event);
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
break;
|
||||
case BUF_FLUSH_N_TYPES:
|
||||
ut_error;
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
|
|
@ -698,18 +746,19 @@ static
|
|||
void
|
||||
buf_dblwr_write_block_to_datafile(
|
||||
/*==============================*/
|
||||
const buf_page_t* bpage) /*!< in: page to write */
|
||||
const buf_page_t* bpage, /*!< in: page to write */
|
||||
bool sync) /*!< in: true if sync IO
|
||||
is requested */
|
||||
{
|
||||
ut_a(bpage);
|
||||
ut_a(buf_page_in_file(bpage));
|
||||
|
||||
/* Increment the counter of I/O operations used
|
||||
for selecting LRU policy. */
|
||||
buf_LRU_stat_inc_io();
|
||||
const ulint flags = sync
|
||||
? OS_FILE_WRITE
|
||||
: OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER;
|
||||
|
||||
if (bpage->zip.data) {
|
||||
fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
|
||||
FALSE, buf_page_get_space(bpage),
|
||||
fil_io(flags, sync, buf_page_get_space(bpage),
|
||||
buf_page_get_zip_size(bpage),
|
||||
buf_page_get_page_no(bpage), 0,
|
||||
buf_page_get_zip_size(bpage),
|
||||
|
|
@ -724,8 +773,7 @@ buf_dblwr_write_block_to_datafile(
|
|||
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
|
||||
buf_dblwr_check_page_lsn(block->frame);
|
||||
|
||||
fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
|
||||
FALSE, buf_block_get_space(block), 0,
|
||||
fil_io(flags, sync, buf_block_get_space(block), 0,
|
||||
buf_block_get_page_no(block), 0, UNIV_PAGE_SIZE,
|
||||
(void*) block->frame, (void*) block);
|
||||
}
|
||||
|
|
@ -747,12 +795,12 @@ buf_dblwr_flush_buffered_writes(void)
|
|||
|
||||
if (!srv_use_doublewrite_buf || buf_dblwr == NULL) {
|
||||
/* Sync the writes to the disk. */
|
||||
buf_flush_sync_datafiles();
|
||||
buf_dblwr_sync_datafiles();
|
||||
return;
|
||||
}
|
||||
|
||||
try_again:
|
||||
mutex_enter(&(buf_dblwr->mutex));
|
||||
mutex_enter(&buf_dblwr->mutex);
|
||||
|
||||
/* Write first to doublewrite buffer blocks. We use synchronous
|
||||
aio and thus know that file write has been completed when the
|
||||
|
|
@ -760,17 +808,18 @@ try_again:
|
|||
|
||||
if (buf_dblwr->first_free == 0) {
|
||||
|
||||
mutex_exit(&(buf_dblwr->mutex));
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (buf_dblwr->batch_running) {
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
|
||||
/* Another thread is running the batch right now. Wait
|
||||
for it to finish. */
|
||||
os_thread_sleep(TRX_DOUBLEWRITE_BATCH_POLL_DELAY);
|
||||
ib_int64_t sig_count = os_event_reset(buf_dblwr->b_event);
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
|
||||
os_event_wait_low(buf_dblwr->b_event, sig_count);
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
|
|
@ -779,7 +828,7 @@ try_again:
|
|||
|
||||
/* Disallow anyone else to post to doublewrite buffer or to
|
||||
start another batch of flushing. */
|
||||
buf_dblwr->batch_running = TRUE;
|
||||
buf_dblwr->batch_running = true;
|
||||
first_free = buf_dblwr->first_free;
|
||||
|
||||
/* Now safe to release the mutex. Note that though no other
|
||||
|
|
@ -818,7 +867,7 @@ try_again:
|
|||
len = ut_min(TRX_SYS_DOUBLEWRITE_BLOCK_SIZE,
|
||||
buf_dblwr->first_free) * UNIV_PAGE_SIZE;
|
||||
|
||||
fil_io(OS_FILE_WRITE, TRUE, TRX_SYS_SPACE, 0,
|
||||
fil_io(OS_FILE_WRITE, true, TRX_SYS_SPACE, 0,
|
||||
buf_dblwr->block1, 0, len,
|
||||
(void*) write_buf, NULL);
|
||||
|
||||
|
|
@ -834,7 +883,7 @@ try_again:
|
|||
write_buf = buf_dblwr->write_buf
|
||||
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE * UNIV_PAGE_SIZE;
|
||||
|
||||
fil_io(OS_FILE_WRITE, TRUE, TRX_SYS_SPACE, 0,
|
||||
fil_io(OS_FILE_WRITE, true, TRX_SYS_SPACE, 0,
|
||||
buf_dblwr->block2, 0, len,
|
||||
(void*) write_buf, NULL);
|
||||
|
||||
|
|
@ -864,7 +913,7 @@ flush:
|
|||
ut_ad(first_free == buf_dblwr->first_free);
|
||||
for (ulint i = 0; i < first_free; i++) {
|
||||
buf_dblwr_write_block_to_datafile(
|
||||
buf_dblwr->buf_block_arr[i]);
|
||||
buf_dblwr->buf_block_arr[i], false);
|
||||
}
|
||||
|
||||
/* Wake possible simulated aio thread to actually post the
|
||||
|
|
@ -889,12 +938,11 @@ buf_dblwr_add_to_batch(
|
|||
ut_a(buf_page_in_file(bpage));
|
||||
|
||||
try_again:
|
||||
mutex_enter(&(buf_dblwr->mutex));
|
||||
mutex_enter(&buf_dblwr->mutex);
|
||||
|
||||
ut_a(buf_dblwr->first_free <= srv_doublewrite_batch_size);
|
||||
|
||||
if (buf_dblwr->batch_running) {
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
|
||||
/* This not nearly as bad as it looks. There is only
|
||||
page_cleaner thread which does background flushing
|
||||
|
|
@ -902,7 +950,10 @@ try_again:
|
|||
point. The only exception is when a user thread is
|
||||
forced to do a flush batch because of a sync
|
||||
checkpoint. */
|
||||
os_thread_sleep(TRX_DOUBLEWRITE_BATCH_POLL_DELAY);
|
||||
ib_int64_t sig_count = os_event_reset(buf_dblwr->b_event);
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
|
||||
os_event_wait_low(buf_dblwr->b_event, sig_count);
|
||||
goto try_again;
|
||||
}
|
||||
|
||||
|
|
@ -967,7 +1018,8 @@ UNIV_INTERN
|
|||
void
|
||||
buf_dblwr_write_single_page(
|
||||
/*========================*/
|
||||
buf_page_t* bpage) /*!< in: buffer block to write */
|
||||
buf_page_t* bpage, /*!< in: buffer block to write */
|
||||
bool sync) /*!< in: true if sync IO requested */
|
||||
{
|
||||
ulint n_slots;
|
||||
ulint size;
|
||||
|
|
@ -1004,11 +1056,12 @@ retry:
|
|||
mutex_enter(&buf_dblwr->mutex);
|
||||
if (buf_dblwr->s_reserved == n_slots) {
|
||||
|
||||
/* All slots are reserved. */
|
||||
ib_int64_t sig_count =
|
||||
os_event_reset(buf_dblwr->s_event);
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
/* All slots are reserved. Since it involves two IOs
|
||||
during the processing a sleep of 10ms should be
|
||||
enough. */
|
||||
os_thread_sleep(TRX_DOUBLEWRITE_BATCH_POLL_DELAY);
|
||||
os_event_wait_low(buf_dblwr->s_event, sig_count);
|
||||
|
||||
goto retry;
|
||||
}
|
||||
|
||||
|
|
@ -1021,9 +1074,14 @@ retry:
|
|||
|
||||
/* We are guaranteed to find a slot. */
|
||||
ut_a(i < size);
|
||||
buf_dblwr->in_use[i] = TRUE;
|
||||
buf_dblwr->in_use[i] = true;
|
||||
buf_dblwr->s_reserved++;
|
||||
buf_dblwr->buf_block_arr[i] = bpage;
|
||||
|
||||
/* increment the doublewrite flushed pages counter */
|
||||
srv_stats.dblwr_pages_written.inc();
|
||||
srv_stats.dblwr_writes.inc();
|
||||
|
||||
mutex_exit(&buf_dblwr->mutex);
|
||||
|
||||
/* Lets see if we are going to write in the first or second
|
||||
|
|
@ -1053,14 +1111,14 @@ retry:
|
|||
memset(buf_dblwr->write_buf + UNIV_PAGE_SIZE * i
|
||||
+ zip_size, 0, UNIV_PAGE_SIZE - zip_size);
|
||||
|
||||
fil_io(OS_FILE_WRITE, TRUE, TRX_SYS_SPACE, 0,
|
||||
fil_io(OS_FILE_WRITE, true, TRX_SYS_SPACE, 0,
|
||||
offset, 0, UNIV_PAGE_SIZE,
|
||||
(void*) (buf_dblwr->write_buf
|
||||
+ UNIV_PAGE_SIZE * i), NULL);
|
||||
} else {
|
||||
/* It is a regular page. Write it directly to the
|
||||
doublewrite buffer */
|
||||
fil_io(OS_FILE_WRITE, TRUE, TRX_SYS_SPACE, 0,
|
||||
fil_io(OS_FILE_WRITE, true, TRX_SYS_SPACE, 0,
|
||||
offset, 0, UNIV_PAGE_SIZE,
|
||||
(void*) ((buf_block_t*) bpage)->frame,
|
||||
NULL);
|
||||
|
|
@ -1072,22 +1130,6 @@ retry:
|
|||
/* We know that the write has been flushed to disk now
|
||||
and during recovery we will find it in the doublewrite buffer
|
||||
blocks. Next do the write to the intended position. */
|
||||
buf_dblwr_write_block_to_datafile(bpage);
|
||||
|
||||
/* Sync the writes to the disk. */
|
||||
buf_flush_sync_datafiles();
|
||||
|
||||
mutex_enter(&buf_dblwr->mutex);
|
||||
|
||||
buf_dblwr->s_reserved--;
|
||||
buf_dblwr->buf_block_arr[i] = NULL;
|
||||
buf_dblwr->in_use[i] = FALSE;
|
||||
|
||||
/* increment the doublewrite flushed pages counter */
|
||||
srv_stats.dblwr_pages_written.inc();
|
||||
srv_stats.dblwr_writes.inc();
|
||||
|
||||
mutex_exit(&(buf_dblwr->mutex));
|
||||
|
||||
buf_dblwr_write_block_to_datafile(bpage, sync);
|
||||
}
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -130,6 +130,60 @@ buf_flush_validate_skip(
|
|||
}
|
||||
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
||||
|
||||
/*******************************************************************//**
|
||||
Sets hazard pointer during flush_list iteration. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_flush_set_hp(
|
||||
/*=============*/
|
||||
buf_pool_t* buf_pool,/*!< in/out: buffer pool instance */
|
||||
const buf_page_t* bpage) /*!< in: buffer control block */
|
||||
{
|
||||
ut_ad(buf_flush_list_mutex_own(buf_pool));
|
||||
ut_ad(buf_pool->flush_list_hp == NULL || bpage == NULL);
|
||||
ut_ad(!bpage || buf_page_in_file(bpage));
|
||||
ut_ad(!bpage || bpage->in_flush_list);
|
||||
ut_ad(!bpage || buf_pool_from_bpage(bpage) == buf_pool);
|
||||
|
||||
buf_pool->flush_list_hp = bpage;
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Checks if the given block is a hazard pointer
|
||||
@return true if bpage is hazard pointer */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
buf_flush_is_hp(
|
||||
/*============*/
|
||||
buf_pool_t* buf_pool,/*!< in: buffer pool instance */
|
||||
const buf_page_t* bpage) /*!< in: buffer control block */
|
||||
{
|
||||
ut_ad(buf_flush_list_mutex_own(buf_pool));
|
||||
|
||||
return(buf_pool->flush_list_hp == bpage);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Whenever we move a block in flush_list (either to remove it or to
|
||||
relocate it) we check the hazard pointer set by some other thread
|
||||
doing the flush list scan. If the hazard pointer is the same as the
|
||||
one we are about going to move then we set it to NULL to force a rescan
|
||||
in the thread doing the batch. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_flush_update_hp(
|
||||
/*================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
buf_page_t* bpage) /*!< in: buffer control block */
|
||||
{
|
||||
ut_ad(buf_flush_list_mutex_own(buf_pool));
|
||||
|
||||
if (buf_flush_is_hp(buf_pool, bpage)) {
|
||||
buf_flush_set_hp(buf_pool, NULL);
|
||||
MONITOR_INC(MONITOR_FLUSH_HP_RESCAN);
|
||||
}
|
||||
}
|
||||
|
||||
/******************************************************************//**
|
||||
Insert a block in the flush_rbt and returns a pointer to its
|
||||
predecessor or NULL if no predecessor. The ordering is maintained
|
||||
|
|
@ -471,34 +525,35 @@ buf_flush_ready_for_replace(
|
|||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Returns TRUE if the block is modified and ready for flushing.
|
||||
@return TRUE if can flush immediately */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
Returns true if the block is modified and ready for flushing.
|
||||
@return true if can flush immediately */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
buf_flush_ready_for_flush(
|
||||
/*======================*/
|
||||
buf_page_t* bpage, /*!< in: buffer control block, must be
|
||||
buf_page_in_file(bpage) */
|
||||
enum buf_flush flush_type)/*!< in: type of flush */
|
||||
buf_flush_t flush_type)/*!< in: type of flush */
|
||||
{
|
||||
#ifdef UNIV_DEBUG
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
#endif
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
ut_a(buf_page_in_file(bpage));
|
||||
ut_ad(mutex_own(buf_page_get_mutex(bpage)));
|
||||
ut_ad(flush_type < BUF_FLUSH_N_TYPES);
|
||||
|
||||
if (bpage->oldest_modification == 0
|
||||
|| buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
|
||||
return(FALSE);
|
||||
return(false);
|
||||
}
|
||||
|
||||
ut_ad(bpage->in_flush_list);
|
||||
|
||||
switch (flush_type) {
|
||||
case BUF_FLUSH_LIST:
|
||||
return(TRUE);
|
||||
return(true);
|
||||
|
||||
case BUF_FLUSH_LRU:
|
||||
case BUF_FLUSH_SINGLE_PAGE:
|
||||
|
|
@ -514,7 +569,7 @@ buf_flush_ready_for_flush(
|
|||
}
|
||||
|
||||
ut_error;
|
||||
return(FALSE);
|
||||
return(false);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
|
|
@ -535,9 +590,9 @@ buf_flush_remove(
|
|||
buf_flush_list_mutex_enter(buf_pool);
|
||||
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
/* Clean compressed pages should not be on the flush list */
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
|
|
@ -574,6 +629,7 @@ buf_flush_remove(
|
|||
ut_a(buf_flush_validate_skip(buf_pool));
|
||||
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
||||
|
||||
buf_flush_update_hp(buf_pool, bpage);
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
}
|
||||
|
||||
|
|
@ -652,6 +708,7 @@ buf_flush_relocate_on_flush_list(
|
|||
ut_a(buf_flush_validate_low(buf_pool));
|
||||
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
||||
|
||||
buf_flush_update_hp(buf_pool, bpage);
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
}
|
||||
|
||||
|
|
@ -663,7 +720,7 @@ buf_flush_write_complete(
|
|||
/*=====================*/
|
||||
buf_page_t* bpage) /*!< in: pointer to the block in question */
|
||||
{
|
||||
enum buf_flush flush_type;
|
||||
buf_flush_t flush_type;
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
|
||||
ut_ad(bpage);
|
||||
|
|
@ -684,18 +741,7 @@ buf_flush_write_complete(
|
|||
os_event_set(buf_pool->no_flush[flush_type]);
|
||||
}
|
||||
|
||||
switch (flush_type) {
|
||||
case BUF_FLUSH_LIST:
|
||||
case BUF_FLUSH_LRU:
|
||||
buf_dblwr_update();
|
||||
break;
|
||||
case BUF_FLUSH_SINGLE_PAGE:
|
||||
/* Single page flushes are synchronous. No need
|
||||
to update doublewrite */
|
||||
break;
|
||||
case BUF_FLUSH_N_TYPES:
|
||||
ut_error;
|
||||
}
|
||||
buf_dblwr_update(bpage, flush_type);
|
||||
}
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
|
|
@ -826,28 +872,6 @@ buf_flush_init_for_writing(
|
|||
}
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
/********************************************************************//**
|
||||
Flush a batch of writes to the datafiles that have already been
|
||||
written by the OS. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
buf_flush_sync_datafiles(void)
|
||||
/*==========================*/
|
||||
{
|
||||
/* Wake possible simulated aio thread to actually post the
|
||||
writes to the operating system */
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
/* Wait that all async writes to tablespaces have been posted to
|
||||
the OS */
|
||||
os_aio_wait_until_no_pending_writes();
|
||||
|
||||
/* Now we flush the data to disk (for example, with fsync) */
|
||||
fil_flush_file_spaces(FIL_TABLESPACE);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Does an asynchronous write of a buffer page. NOTE: in simulated aio and
|
||||
also when the doublewrite buffer is used, we must call
|
||||
|
|
@ -858,7 +882,8 @@ void
|
|||
buf_flush_write_block_low(
|
||||
/*======================*/
|
||||
buf_page_t* bpage, /*!< in: buffer block to write */
|
||||
enum buf_flush flush_type) /*!< in: type of flush */
|
||||
buf_flush_t flush_type, /*!< in: type of flush */
|
||||
bool sync) /*!< in: true if sync IO request */
|
||||
{
|
||||
ulint zip_size = buf_page_get_zip_size(bpage);
|
||||
page_t* frame = NULL;
|
||||
|
|
@ -903,7 +928,7 @@ buf_flush_write_block_low(
|
|||
log_write_up_to(bpage->newest_modification, LOG_WAIT_ALL_GROUPS, TRUE);
|
||||
#endif
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE: /* The page should be dirty. */
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
|
|
@ -935,15 +960,29 @@ buf_flush_write_block_low(
|
|||
|
||||
if (!srv_use_doublewrite_buf || !buf_dblwr) {
|
||||
fil_io(OS_FILE_WRITE | OS_AIO_SIMULATED_WAKE_LATER,
|
||||
FALSE, buf_page_get_space(bpage), zip_size,
|
||||
sync, buf_page_get_space(bpage), zip_size,
|
||||
buf_page_get_page_no(bpage), 0,
|
||||
zip_size ? zip_size : UNIV_PAGE_SIZE,
|
||||
frame, bpage);
|
||||
} else if (flush_type == BUF_FLUSH_SINGLE_PAGE) {
|
||||
buf_dblwr_write_single_page(bpage);
|
||||
buf_dblwr_write_single_page(bpage, sync);
|
||||
} else {
|
||||
ut_ad(!sync);
|
||||
buf_dblwr_add_to_batch(bpage);
|
||||
}
|
||||
|
||||
/* When doing single page flushing the IO is done synchronously
|
||||
and we flush the changes to disk only for the tablespace we
|
||||
are working on. */
|
||||
if (sync) {
|
||||
ut_ad(flush_type == BUF_FLUSH_SINGLE_PAGE);
|
||||
fil_flush(buf_page_get_space(bpage));
|
||||
buf_page_io_complete(bpage);
|
||||
}
|
||||
|
||||
/* Increment the counter of I/O operations used
|
||||
for selecting LRU policy. */
|
||||
buf_LRU_stat_inc_io();
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
|
|
@ -959,7 +998,8 @@ buf_flush_page(
|
|||
/*===========*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
buf_page_t* bpage, /*!< in: buffer control block */
|
||||
buf_flush flush_type) /*!< in: type of flush */
|
||||
buf_flush_t flush_type, /*!< in: type of flush */
|
||||
bool sync) /*!< in: true if sync IO request */
|
||||
{
|
||||
ib_mutex_t* block_mutex;
|
||||
ibool is_uncompressed;
|
||||
|
|
@ -967,6 +1007,7 @@ buf_flush_page(
|
|||
ut_ad(flush_type < BUF_FLUSH_N_TYPES);
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_ad(buf_page_in_file(bpage));
|
||||
ut_ad(!sync || flush_type == BUF_FLUSH_SINGLE_PAGE);
|
||||
|
||||
block_mutex = buf_page_get_mutex(bpage);
|
||||
ut_ad(mutex_own(block_mutex));
|
||||
|
|
@ -1062,7 +1103,7 @@ buf_flush_page(
|
|||
flush_type, bpage->space, bpage->offset);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
buf_flush_write_block_low(bpage, flush_type);
|
||||
buf_flush_write_block_low(bpage, flush_type, sync);
|
||||
}
|
||||
|
||||
# if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
|
||||
|
|
@ -1089,8 +1130,7 @@ buf_flush_page_try(
|
|||
|
||||
/* The following call will release the buffer pool and
|
||||
block mutex. */
|
||||
buf_flush_page(buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE);
|
||||
buf_flush_sync_datafiles();
|
||||
buf_flush_page(buf_pool, &block->page, BUF_FLUSH_SINGLE_PAGE, true);
|
||||
return(TRUE);
|
||||
}
|
||||
# endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
|
||||
|
|
@ -1103,7 +1143,7 @@ buf_flush_check_neighbor(
|
|||
/*=====================*/
|
||||
ulint space, /*!< in: space id */
|
||||
ulint offset, /*!< in: page offset */
|
||||
enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU or
|
||||
buf_flush_t flush_type) /*!< in: BUF_FLUSH_LRU or
|
||||
BUF_FLUSH_LIST */
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
|
|
@ -1153,7 +1193,7 @@ buf_flush_try_neighbors(
|
|||
/*====================*/
|
||||
ulint space, /*!< in: space id */
|
||||
ulint offset, /*!< in: page offset */
|
||||
enum buf_flush flush_type, /*!< in: BUF_FLUSH_LRU or
|
||||
buf_flush_t flush_type, /*!< in: BUF_FLUSH_LRU or
|
||||
BUF_FLUSH_LIST */
|
||||
ulint n_flushed, /*!< in: number of pages
|
||||
flushed so far in this batch */
|
||||
|
|
@ -1274,7 +1314,7 @@ buf_flush_try_neighbors(
|
|||
doublewrite buffer before we start
|
||||
waiting. */
|
||||
|
||||
buf_flush_page(buf_pool, bpage, flush_type);
|
||||
buf_flush_page(buf_pool, bpage, flush_type, false);
|
||||
ut_ad(!mutex_own(block_mutex));
|
||||
ut_ad(!buf_pool_mutex_own(buf_pool));
|
||||
count++;
|
||||
|
|
@ -1311,7 +1351,7 @@ buf_flush_page_and_try_neighbors(
|
|||
buf_page_t* bpage, /*!< in: buffer control block,
|
||||
must be
|
||||
buf_page_in_file(bpage) */
|
||||
enum buf_flush flush_type, /*!< in: BUF_FLUSH_LRU
|
||||
buf_flush_t flush_type, /*!< in: BUF_FLUSH_LRU
|
||||
or BUF_FLUSH_LIST */
|
||||
ulint n_to_flush, /*!< in: number of pages to
|
||||
flush */
|
||||
|
|
@ -1396,7 +1436,7 @@ buf_free_from_unzip_LRU_list_batch(
|
|||
&& lru_len > UT_LIST_GET_LEN(buf_pool->LRU) / 10) {
|
||||
|
||||
++scanned;
|
||||
if (buf_LRU_free_block(&block->page, FALSE)) {
|
||||
if (buf_LRU_free_page(&block->page, false)) {
|
||||
/* Block was freed. buf_pool->mutex potentially
|
||||
released and reacquired */
|
||||
++count;
|
||||
|
|
@ -1473,7 +1513,7 @@ buf_flush_LRU_list_batch(
|
|||
of the flushed pages then the scan becomes
|
||||
O(n*n). */
|
||||
if (evict) {
|
||||
if (buf_LRU_free_block(bpage, TRUE)) {
|
||||
if (buf_LRU_free_page(bpage, true)) {
|
||||
/* buf_pool->mutex was potentially
|
||||
released and reacquired. */
|
||||
bpage = UT_LIST_GET_LAST(buf_pool->LRU);
|
||||
|
|
@ -1561,82 +1601,62 @@ buf_do_flush_list_batch(
|
|||
their number does not exceed
|
||||
min_n) */
|
||||
{
|
||||
ulint len;
|
||||
buf_page_t* bpage;
|
||||
ulint count = 0;
|
||||
ulint scanned = 0;
|
||||
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
|
||||
/* If we have flushed enough, leave the loop */
|
||||
do {
|
||||
/* Start from the end of the list looking for a suitable
|
||||
block to be flushed. */
|
||||
|
||||
buf_flush_list_mutex_enter(buf_pool);
|
||||
ulint len = UT_LIST_GET_LEN(buf_pool->flush_list);
|
||||
|
||||
/* We use len here because theoretically insertions can
|
||||
happen in the flush_list below while we are traversing
|
||||
it for a suitable candidate for flushing. We'd like to
|
||||
set a limit on how farther we are willing to traverse
|
||||
the list. */
|
||||
len = UT_LIST_GET_LEN(buf_pool->flush_list);
|
||||
bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
|
||||
/* In order not to degenerate this scan to O(n*n) we attempt
|
||||
to preserve pointer of previous block in the flush list. To do
|
||||
so we declare it a hazard pointer. Any thread working on the
|
||||
flush list must check the hazard pointer and if it is removing
|
||||
the same block then it must reset it. */
|
||||
for (buf_page_t* bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
|
||||
count < min_n && bpage != NULL && len > 0
|
||||
&& bpage->oldest_modification < lsn_limit;
|
||||
++scanned) {
|
||||
|
||||
if (bpage) {
|
||||
ut_a(bpage->oldest_modification > 0);
|
||||
}
|
||||
|
||||
if (!bpage || bpage->oldest_modification >= lsn_limit) {
|
||||
|
||||
/* We have flushed enough */
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
break;
|
||||
}
|
||||
buf_page_t* prev;
|
||||
|
||||
ut_a(bpage->oldest_modification > 0);
|
||||
|
||||
ut_ad(bpage->in_flush_list);
|
||||
|
||||
prev = UT_LIST_GET_PREV(list, bpage);
|
||||
buf_flush_set_hp(buf_pool, prev);
|
||||
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
|
||||
/* The list may change during the flushing and we cannot
|
||||
safely preserve within this function a pointer to a
|
||||
block in the list! */
|
||||
while (bpage != NULL
|
||||
&& len > 0
|
||||
&& !buf_flush_page_and_try_neighbors(
|
||||
bpage, BUF_FLUSH_LIST, min_n, &count)) {
|
||||
#ifdef UNIV_DEBUG
|
||||
bool flushed =
|
||||
#endif /* UNIV_DEBUG */
|
||||
buf_flush_page_and_try_neighbors(
|
||||
bpage, BUF_FLUSH_LIST, min_n, &count);
|
||||
|
||||
++scanned;
|
||||
buf_flush_list_mutex_enter(buf_pool);
|
||||
|
||||
/* If we are here that means that buf_pool->mutex
|
||||
was not released in buf_flush_page_and_try_neighbors()
|
||||
above and this guarantees that bpage didn't get
|
||||
relocated since we released the flush_list
|
||||
mutex above. There is a chance, however, that
|
||||
the bpage got removed from flush_list (not
|
||||
currently possible because flush_list_remove()
|
||||
also obtains buf_pool mutex but that may change
|
||||
in future). To avoid this scenario we check
|
||||
the oldest_modification and if it is zero
|
||||
we start all over again. */
|
||||
if (bpage->oldest_modification == 0) {
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
break;
|
||||
}
|
||||
ut_ad(flushed || buf_flush_is_hp(buf_pool, prev));
|
||||
|
||||
bpage = UT_LIST_GET_PREV(list, bpage);
|
||||
if (!buf_flush_is_hp(buf_pool, prev)) {
|
||||
/* The hazard pointer was reset by some other
|
||||
thread. Restart the scan. */
|
||||
ut_ad(buf_flush_is_hp(buf_pool, NULL));
|
||||
bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
|
||||
len = UT_LIST_GET_LEN(buf_pool->flush_list);
|
||||
} else {
|
||||
bpage = prev;
|
||||
--len;
|
||||
buf_flush_set_hp(buf_pool, NULL);
|
||||
}
|
||||
|
||||
ut_ad(!bpage || bpage->in_flush_list);
|
||||
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
|
||||
--len;
|
||||
}
|
||||
|
||||
} while (count < min_n && bpage != NULL && len > 0);
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
|
||||
MONITOR_INC_VALUE_CUMULATIVE(MONITOR_FLUSH_BATCH_SCANNED,
|
||||
MONITOR_FLUSH_BATCH_SCANNED_NUM_CALL,
|
||||
|
|
@ -1660,7 +1680,7 @@ ulint
|
|||
buf_flush_batch(
|
||||
/*============*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
enum buf_flush flush_type, /*!< in: BUF_FLUSH_LRU or
|
||||
buf_flush_t flush_type, /*!< in: BUF_FLUSH_LRU or
|
||||
BUF_FLUSH_LIST; if BUF_FLUSH_LIST,
|
||||
then the caller must not own any
|
||||
latches on pages */
|
||||
|
|
@ -1716,7 +1736,7 @@ static
|
|||
void
|
||||
buf_flush_common(
|
||||
/*=============*/
|
||||
enum buf_flush flush_type, /*!< in: type of flush */
|
||||
buf_flush_t flush_type, /*!< in: type of flush */
|
||||
ulint page_count) /*!< in: number of pages flushed */
|
||||
{
|
||||
buf_dblwr_flush_buffered_writes();
|
||||
|
|
@ -1742,7 +1762,7 @@ ibool
|
|||
buf_flush_start(
|
||||
/*============*/
|
||||
buf_pool_t* buf_pool, /*!< buffer pool instance */
|
||||
enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU
|
||||
buf_flush_t flush_type) /*!< in: BUF_FLUSH_LRU
|
||||
or BUF_FLUSH_LIST */
|
||||
{
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
|
|
@ -1771,7 +1791,7 @@ void
|
|||
buf_flush_end(
|
||||
/*==========*/
|
||||
buf_pool_t* buf_pool, /*!< buffer pool instance */
|
||||
enum buf_flush flush_type) /*!< in: BUF_FLUSH_LRU
|
||||
buf_flush_t flush_type) /*!< in: BUF_FLUSH_LRU
|
||||
or BUF_FLUSH_LIST */
|
||||
{
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
|
|
@ -1797,7 +1817,7 @@ void
|
|||
buf_flush_wait_batch_end(
|
||||
/*=====================*/
|
||||
buf_pool_t* buf_pool, /*!< buffer pool instance */
|
||||
enum buf_flush type) /*!< in: BUF_FLUSH_LRU
|
||||
buf_flush_t type) /*!< in: BUF_FLUSH_LRU
|
||||
or BUF_FLUSH_LIST */
|
||||
{
|
||||
ut_ad(type == BUF_FLUSH_LRU || type == BUF_FLUSH_LIST);
|
||||
|
|
@ -1967,7 +1987,7 @@ buf_flush_single_page_from_LRU(
|
|||
buf_page_t* bpage;
|
||||
ib_mutex_t* block_mutex;
|
||||
ibool freed;
|
||||
ibool evict_zip;
|
||||
bool evict_zip;
|
||||
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
|
||||
|
|
@ -2000,9 +2020,7 @@ buf_flush_single_page_from_LRU(
|
|||
|
||||
/* The following call will release the buffer pool and
|
||||
block mutex. */
|
||||
buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE);
|
||||
|
||||
buf_flush_sync_datafiles();
|
||||
buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, true);
|
||||
|
||||
/* At this point the page has been written to the disk.
|
||||
As we are not holding buffer pool or block mutex therefore
|
||||
|
|
@ -2037,7 +2055,7 @@ buf_flush_single_page_from_LRU(
|
|||
|
||||
evict_zip = !buf_LRU_evict_from_unzip_LRU(buf_pool);;
|
||||
|
||||
freed = buf_LRU_free_block(bpage, evict_zip);
|
||||
freed = buf_LRU_free_page(bpage, evict_zip);
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
|
||||
return(freed);
|
||||
|
|
@ -2060,12 +2078,21 @@ buf_flush_LRU_tail(void)
|
|||
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
|
||||
|
||||
buf_pool_t* buf_pool = buf_pool_from_array(i);
|
||||
ulint scan_depth;
|
||||
|
||||
/* srv_LRU_scan_depth can be arbitrarily large value.
|
||||
We cap it with current LRU size. */
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
scan_depth = UT_LIST_GET_LEN(buf_pool->LRU);
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
|
||||
scan_depth = ut_min(srv_LRU_scan_depth, scan_depth);
|
||||
|
||||
/* We divide LRU flush into smaller chunks because
|
||||
there may be user threads waiting for the flush to
|
||||
end in buf_LRU_get_free_block(). */
|
||||
for (ulint j = 0;
|
||||
j < srv_LRU_scan_depth;
|
||||
j < scan_depth;
|
||||
j += PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE) {
|
||||
|
||||
ulint n_flushed = 0;
|
||||
|
|
@ -2074,11 +2101,22 @@ buf_flush_LRU_tail(void)
|
|||
that can trigger an LRU flush. It is possible
|
||||
that a batch triggered during last iteration is
|
||||
still running, */
|
||||
buf_flush_LRU(buf_pool,
|
||||
if (buf_flush_LRU(buf_pool,
|
||||
PAGE_CLEANER_LRU_BATCH_CHUNK_SIZE,
|
||||
&n_flushed);
|
||||
&n_flushed)) {
|
||||
|
||||
/* Allowed only one batch per
|
||||
buffer pool instance. */
|
||||
buf_flush_wait_batch_end(
|
||||
buf_pool, BUF_FLUSH_LRU);
|
||||
}
|
||||
|
||||
if (n_flushed) {
|
||||
total_flushed += n_flushed;
|
||||
} else {
|
||||
/* Nothing to flush */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -2272,9 +2310,9 @@ page_cleaner_flush_pages_if_needed(void)
|
|||
|
||||
oldest_lsn = buf_pool_get_oldest_modification();
|
||||
|
||||
ut_ad(oldest_lsn <= cur_lsn);
|
||||
ut_ad(oldest_lsn <= log_get_lsn());
|
||||
|
||||
age = cur_lsn - oldest_lsn;
|
||||
age = cur_lsn > oldest_lsn ? cur_lsn - oldest_lsn : 0;
|
||||
|
||||
pct_for_dirty = af_get_pct_for_dirty();
|
||||
pct_for_lsn = af_get_pct_for_lsn(age);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
|
|
@ -137,19 +137,19 @@ The caller must hold buf_pool->mutex, the buf_page_get_mutex() mutex
|
|||
and the appropriate hash_lock. This function will release the
|
||||
buf_page_get_mutex() and the hash_lock.
|
||||
|
||||
If a compressed page or a compressed-only block descriptor is freed,
|
||||
other compressed pages or compressed-only block descriptors may be
|
||||
relocated.
|
||||
@return the new state of the block (BUF_BLOCK_ZIP_FREE if the state
|
||||
was BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH otherwise) */
|
||||
static
|
||||
enum buf_page_state
|
||||
buf_LRU_block_remove_hashed_page(
|
||||
/*=============================*/
|
||||
If a compressed page is freed other compressed pages may be relocated.
|
||||
@retval true if BUF_BLOCK_FILE_PAGE was removed from page_hash. The
|
||||
caller needs to free the page to the free list
|
||||
@retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In
|
||||
this case the block is already returned to the buddy allocator. */
|
||||
static __attribute__((nonnull, warn_unused_result))
|
||||
bool
|
||||
buf_LRU_block_remove_hashed(
|
||||
/*========================*/
|
||||
buf_page_t* bpage, /*!< in: 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 */
|
||||
ibool zip); /*!< in: TRUE if should remove also the
|
||||
bool zip); /*!< in: true if should remove also the
|
||||
compressed page of an uncompressed page */
|
||||
/******************************************************************//**
|
||||
Puts a file page whose has no hash index to the free list. */
|
||||
|
|
@ -460,14 +460,9 @@ buf_flush_or_remove_page(
|
|||
don't remove else remove without
|
||||
flushing to disk */
|
||||
{
|
||||
ib_mutex_t* block_mutex;
|
||||
bool processed = false;
|
||||
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
ut_ad(buf_flush_list_mutex_own(buf_pool));
|
||||
|
||||
block_mutex = buf_page_get_mutex(bpage);
|
||||
|
||||
/* bpage->space and bpage->io_fix are protected by
|
||||
buf_pool->mutex and block_mutex. It is safe to check
|
||||
them while holding buf_pool->mutex only. */
|
||||
|
|
@ -477,13 +472,18 @@ buf_flush_or_remove_page(
|
|||
/* We cannot remove this page during this scan
|
||||
yet; maybe the system is currently reading it
|
||||
in, or flushing the modifications to the file */
|
||||
return(false);
|
||||
|
||||
} else {
|
||||
}
|
||||
|
||||
ib_mutex_t* block_mutex = buf_page_get_mutex(bpage);
|
||||
bool processed = false;
|
||||
|
||||
/* We have to release the flush_list_mutex to obey the
|
||||
latching order. We are however guaranteed that the page
|
||||
will stay in the flush_list because buf_flush_remove()
|
||||
needs buf_pool->mutex as well (for the non-flush case). */
|
||||
will stay in the flush_list and won't be relocated because
|
||||
buf_flush_remove() and buf_flush_relocate_on_flush_list()
|
||||
need buf_pool->mutex as well. */
|
||||
|
||||
buf_flush_list_mutex_exit(buf_pool);
|
||||
|
||||
|
|
@ -491,16 +491,7 @@ buf_flush_or_remove_page(
|
|||
|
||||
ut_ad(bpage->oldest_modification != 0);
|
||||
|
||||
if (bpage->buf_fix_count > 0) {
|
||||
|
||||
mutex_exit(block_mutex);
|
||||
|
||||
/* We cannot remove this page yet;
|
||||
maybe the system is currently reading
|
||||
it in, or flushing the modifications
|
||||
to the file */
|
||||
|
||||
} else if (!flush) {
|
||||
if (!flush) {
|
||||
|
||||
buf_flush_remove(bpage);
|
||||
|
||||
|
|
@ -508,16 +499,13 @@ buf_flush_or_remove_page(
|
|||
|
||||
processed = true;
|
||||
|
||||
} else if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
|
||||
|
||||
/* Check the status again after releasing the flush
|
||||
list mutex and acquiring the block mutex. The background
|
||||
flush thread may be in the process of flushing this
|
||||
page when we released the flush list mutex. */
|
||||
} else if (buf_flush_ready_for_flush(bpage,
|
||||
BUF_FLUSH_SINGLE_PAGE)) {
|
||||
|
||||
/* The following call will release the buffer pool
|
||||
and block mutex. */
|
||||
buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE);
|
||||
buf_flush_page(buf_pool, bpage, BUF_FLUSH_SINGLE_PAGE, false);
|
||||
ut_ad(!mutex_own(block_mutex));
|
||||
|
||||
/* Wake possible simulated aio thread to actually
|
||||
post the writes to the operating system */
|
||||
|
|
@ -527,13 +515,17 @@ buf_flush_or_remove_page(
|
|||
|
||||
processed = true;
|
||||
} else {
|
||||
/* Not ready for flush. It can't be IO fixed because we
|
||||
checked for that at the start of the function. It must
|
||||
be buffer fixed. */
|
||||
ut_ad(bpage->buf_fix_count > 0);
|
||||
mutex_exit(block_mutex);
|
||||
}
|
||||
|
||||
buf_flush_list_mutex_enter(buf_pool);
|
||||
}
|
||||
|
||||
ut_ad(!mutex_own(block_mutex));
|
||||
ut_ad(buf_pool_mutex_own(buf_pool));
|
||||
|
||||
return(processed);
|
||||
}
|
||||
|
|
@ -562,10 +554,12 @@ buf_flush_or_remove_pages(
|
|||
buf_page_t* prev;
|
||||
buf_page_t* bpage;
|
||||
ulint processed = 0;
|
||||
bool all_freed = true;
|
||||
|
||||
buf_flush_list_mutex_enter(buf_pool);
|
||||
|
||||
rescan:
|
||||
bool all_freed = true;
|
||||
|
||||
for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
|
||||
bpage != NULL;
|
||||
bpage = prev) {
|
||||
|
|
@ -585,9 +579,33 @@ buf_flush_or_remove_pages(
|
|||
} else if (!buf_flush_or_remove_page(buf_pool, bpage, flush)) {
|
||||
|
||||
/* Remove was unsuccessful, we have to try again
|
||||
by scanning the entire list from the end. */
|
||||
by scanning the entire list from the end.
|
||||
This also means that we never released the
|
||||
buf_pool mutex. Therefore we can trust the prev
|
||||
pointer.
|
||||
buf_flush_or_remove_page() released the
|
||||
flush list mutex but not the buf_pool mutex.
|
||||
Therefore it is possible that a new page was
|
||||
added to the flush list. For example, in case
|
||||
where we are at the head of the flush list and
|
||||
prev == NULL. That is OK because we have the
|
||||
tablespace quiesced and no new pages for this
|
||||
space-id should enter flush_list. This is
|
||||
because the only callers of this function are
|
||||
DROP TABLE and FLUSH TABLE FOR EXPORT.
|
||||
We know that we'll have to do at least one more
|
||||
scan but we don't break out of loop here and
|
||||
try to do as much work as we can in this
|
||||
iteration. */
|
||||
|
||||
all_freed = false;
|
||||
} else if (flush) {
|
||||
|
||||
/* The processing was successful. And during the
|
||||
processing we have released the buf_pool mutex
|
||||
when calling buf_page_flush(). We cannot trust
|
||||
prev pointer. */
|
||||
goto rescan;
|
||||
}
|
||||
|
||||
++processed;
|
||||
|
|
@ -649,7 +667,7 @@ buf_flush_dirty_pages(
|
|||
ut_ad(buf_flush_validate(buf_pool));
|
||||
|
||||
if (err == DB_FAIL) {
|
||||
os_thread_sleep(20000);
|
||||
os_thread_sleep(2000);
|
||||
}
|
||||
|
||||
/* DB_FAIL is a soft error, it means that the task wasn't
|
||||
|
|
@ -658,6 +676,9 @@ buf_flush_dirty_pages(
|
|||
ut_ad(buf_flush_validate(buf_pool));
|
||||
|
||||
} while (err == DB_FAIL);
|
||||
|
||||
ut_ad(err == DB_INTERRUPTED
|
||||
|| buf_pool_get_dirty_pages_count(buf_pool, id) == 0);
|
||||
}
|
||||
|
||||
/******************************************************************//**
|
||||
|
|
@ -778,22 +799,16 @@ scan_again:
|
|||
|
||||
/* Remove from the LRU list. */
|
||||
|
||||
if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
|
||||
!= BUF_BLOCK_ZIP_FREE) {
|
||||
|
||||
if (buf_LRU_block_remove_hashed(bpage, true)) {
|
||||
buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
|
||||
|
||||
} else {
|
||||
/* The block_mutex should have been released
|
||||
by buf_LRU_block_remove_hashed_page() when it
|
||||
returns BUF_BLOCK_ZIP_FREE. */
|
||||
ut_ad(block_mutex == &buf_pool->zip_mutex);
|
||||
}
|
||||
|
||||
ut_ad(!mutex_own(block_mutex));
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
/* buf_LRU_block_remove_hashed_page() releases the hash_lock */
|
||||
/* buf_LRU_block_remove_hashed() releases the hash_lock */
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX));
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_SHARED));
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
|
@ -835,15 +850,11 @@ buf_LRU_remove_pages(
|
|||
case BUF_REMOVE_FLUSH_NO_WRITE:
|
||||
ut_a(trx == 0);
|
||||
buf_flush_dirty_pages(buf_pool, id, false, NULL);
|
||||
ut_ad(trx_is_interrupted(trx)
|
||||
|| buf_pool_get_dirty_pages_count(buf_pool, id) == 0);
|
||||
break;
|
||||
|
||||
case BUF_REMOVE_FLUSH_WRITE:
|
||||
ut_a(trx != 0);
|
||||
buf_flush_dirty_pages(buf_pool, id, true, trx);
|
||||
ut_ad(trx_is_interrupted(trx)
|
||||
|| buf_pool_get_dirty_pages_count(buf_pool, id) == 0);
|
||||
/* Ensure that all asynchronous IO is completed. */
|
||||
os_aio_wait_until_no_pending_writes();
|
||||
fil_flush(id);
|
||||
|
|
@ -880,10 +891,14 @@ buf_LRU_flush_or_remove_pages(
|
|||
|
||||
switch (buf_remove) {
|
||||
case BUF_REMOVE_ALL_NO_WRITE:
|
||||
case BUF_REMOVE_FLUSH_NO_WRITE:
|
||||
buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
|
||||
break;
|
||||
|
||||
case BUF_REMOVE_FLUSH_NO_WRITE:
|
||||
/* It is a DROP TABLE for a single table
|
||||
tablespace. No AHI entries exist because
|
||||
we already dealt with them when freeing up
|
||||
extents. */
|
||||
case BUF_REMOVE_FLUSH_WRITE:
|
||||
/* We allow read-only queries against the
|
||||
table, there is no need to drop the AHI entries. */
|
||||
|
|
@ -892,13 +907,6 @@ buf_LRU_flush_or_remove_pages(
|
|||
|
||||
buf_LRU_remove_pages(buf_pool, id, buf_remove, trx);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
if (trx != 0 && id != 0) {
|
||||
ut_ad(trx_is_interrupted(trx)
|
||||
|| buf_flush_get_dirty_pages_count(id) == 0);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
}
|
||||
|
||||
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
|
||||
|
|
@ -972,7 +980,7 @@ buf_LRU_free_from_unzip_LRU_list(
|
|||
ut_ad(block->in_unzip_LRU_list);
|
||||
ut_ad(block->page.in_LRU_list);
|
||||
|
||||
freed = buf_LRU_free_block(&block->page, FALSE);
|
||||
freed = buf_LRU_free_page(&block->page, false);
|
||||
|
||||
block = prev_block;
|
||||
}
|
||||
|
|
@ -1017,7 +1025,7 @@ buf_LRU_free_from_common_LRU_list(
|
|||
ut_ad(bpage->in_LRU_list);
|
||||
|
||||
accessed = buf_page_is_accessed(bpage);
|
||||
freed = buf_LRU_free_block(bpage, TRUE);
|
||||
freed = buf_LRU_free_page(bpage, true);
|
||||
if (freed && !accessed) {
|
||||
/* Keep track of pages that are evicted without
|
||||
ever being accessed. This gives us a measure of
|
||||
|
|
@ -1788,24 +1796,23 @@ buf_LRU_make_block_old(
|
|||
Try to free a block. If bpage is a descriptor of a compressed-only
|
||||
page, the descriptor object will be freed as well.
|
||||
|
||||
NOTE: If this function returns TRUE, it will temporarily
|
||||
NOTE: If this function returns true, it will temporarily
|
||||
release buf_pool->mutex. Furthermore, the page frame will no longer be
|
||||
accessible via bpage.
|
||||
|
||||
The caller must hold buf_pool->mutex and must not hold any
|
||||
buf_page_get_mutex() when calling this function.
|
||||
@return TRUE if freed, FALSE otherwise. */
|
||||
@return true if freed, false otherwise. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
buf_LRU_free_block(
|
||||
bool
|
||||
buf_LRU_free_page(
|
||||
/*===============*/
|
||||
buf_page_t* bpage, /*!< in: block to be freed */
|
||||
ibool zip) /*!< in: TRUE if should remove also the
|
||||
bool zip) /*!< in: true if should remove also the
|
||||
compressed page of an uncompressed page */
|
||||
{
|
||||
buf_page_t* b = NULL;
|
||||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
enum buf_page_state page_state;
|
||||
const ulint fold = buf_page_address_fold(bpage->space,
|
||||
bpage->offset);
|
||||
rw_lock_t* hash_lock = buf_page_hash_lock_get(buf_pool, fold);
|
||||
|
|
@ -1853,7 +1860,7 @@ buf_LRU_free_block(
|
|||
func_exit:
|
||||
rw_lock_x_unlock(hash_lock);
|
||||
mutex_exit(block_mutex);
|
||||
return(FALSE);
|
||||
return(false);
|
||||
|
||||
} else if (buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE) {
|
||||
b = buf_page_alloc_descriptor();
|
||||
|
|
@ -1885,20 +1892,16 @@ func_exit:
|
|||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ut_ad(buf_page_can_relocate(bpage));
|
||||
|
||||
page_state = buf_LRU_block_remove_hashed_page(bpage, zip);
|
||||
if (!buf_LRU_block_remove_hashed(bpage, zip)) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
/* buf_LRU_block_remove_hashed_page() releases the hash_lock */
|
||||
/* buf_LRU_block_remove_hashed() releases the hash_lock */
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)
|
||||
&& !rw_lock_own(hash_lock, RW_LOCK_SHARED));
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
if (page_state == BUF_BLOCK_ZIP_FREE) {
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
ut_ad(page_state == BUF_BLOCK_REMOVE_HASH);
|
||||
|
||||
/* We have just freed a BUF_BLOCK_FILE_PAGE. If b != NULL
|
||||
then it was a compressed page with an uncompressed frame and
|
||||
we are interested in freeing only the uncompressed frame.
|
||||
|
|
@ -1926,7 +1929,7 @@ func_exit:
|
|||
/* The fields in_page_hash and in_LRU_list of
|
||||
the to-be-freed block descriptor should have
|
||||
been cleared in
|
||||
buf_LRU_block_remove_hashed_page(), which
|
||||
buf_LRU_block_remove_hashed(), which
|
||||
invokes buf_LRU_remove_block(). */
|
||||
ut_ad(!bpage->in_page_hash);
|
||||
ut_ad(!bpage->in_LRU_list);
|
||||
|
|
@ -1935,7 +1938,7 @@ func_exit:
|
|||
ut_ad(!((buf_block_t*) bpage)->in_unzip_LRU_list);
|
||||
|
||||
/* The fields of bpage were copied to b before
|
||||
buf_LRU_block_remove_hashed_page() was invoked. */
|
||||
buf_LRU_block_remove_hashed() was invoked. */
|
||||
ut_ad(!b->in_zip_hash);
|
||||
ut_ad(b->in_page_hash);
|
||||
ut_ad(b->in_LRU_list);
|
||||
|
|
@ -2037,7 +2040,7 @@ func_exit:
|
|||
|
||||
/* Remove possible adaptive hash index on the page.
|
||||
The page was declared uninitialized by
|
||||
buf_LRU_block_remove_hashed_page(). We need to flag
|
||||
buf_LRU_block_remove_hashed(). We need to flag
|
||||
the contents of the page valid (which it still is) in
|
||||
order to avoid bogus Valgrind warnings.*/
|
||||
|
||||
|
|
@ -2073,7 +2076,7 @@ func_exit:
|
|||
mutex_exit(block_mutex);
|
||||
|
||||
buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
|
||||
return(TRUE);
|
||||
return(true);
|
||||
}
|
||||
|
||||
/******************************************************************//**
|
||||
|
|
@ -2147,19 +2150,19 @@ The caller must hold buf_pool->mutex, the buf_page_get_mutex() mutex
|
|||
and the appropriate hash_lock. This function will release the
|
||||
buf_page_get_mutex() and the hash_lock.
|
||||
|
||||
If a compressed page or a compressed-only block descriptor is freed,
|
||||
other compressed pages or compressed-only block descriptors may be
|
||||
relocated.
|
||||
@return the new state of the block (BUF_BLOCK_ZIP_FREE if the state
|
||||
was BUF_BLOCK_ZIP_PAGE, or BUF_BLOCK_REMOVE_HASH otherwise) */
|
||||
If a compressed page is freed other compressed pages may be relocated.
|
||||
@retval true if BUF_BLOCK_FILE_PAGE was removed from page_hash. The
|
||||
caller needs to free the page to the free list
|
||||
@retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In
|
||||
this case the block is already returned to the buddy allocator. */
|
||||
static
|
||||
enum buf_page_state
|
||||
buf_LRU_block_remove_hashed_page(
|
||||
/*=============================*/
|
||||
bool
|
||||
buf_LRU_block_remove_hashed(
|
||||
/*========================*/
|
||||
buf_page_t* bpage, /*!< in: 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 */
|
||||
ibool zip) /*!< in: TRUE if should remove also the
|
||||
bool zip) /*!< in: true if should remove also the
|
||||
compressed page of an uncompressed page */
|
||||
{
|
||||
ulint fold;
|
||||
|
|
@ -2252,7 +2255,7 @@ buf_LRU_block_remove_hashed_page(
|
|||
UNIV_MEM_ASSERT_W(bpage->zip.data,
|
||||
page_zip_get_size(&bpage->zip));
|
||||
break;
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
|
|
@ -2319,7 +2322,7 @@ buf_LRU_block_remove_hashed_page(
|
|||
|
||||
buf_pool_mutex_exit_allow(buf_pool);
|
||||
buf_page_free_descriptor(bpage);
|
||||
return(BUF_BLOCK_ZIP_FREE);
|
||||
return(false);
|
||||
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
memset(((buf_block_t*) bpage)->frame
|
||||
|
|
@ -2370,9 +2373,9 @@ buf_LRU_block_remove_hashed_page(
|
|||
page_zip_set_size(&bpage->zip, 0);
|
||||
}
|
||||
|
||||
return(BUF_BLOCK_REMOVE_HASH);
|
||||
return(true);
|
||||
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
|
|
@ -2382,7 +2385,7 @@ buf_LRU_block_remove_hashed_page(
|
|||
}
|
||||
|
||||
ut_error;
|
||||
return(BUF_BLOCK_ZIP_FREE);
|
||||
return(false);
|
||||
}
|
||||
|
||||
/******************************************************************//**
|
||||
|
|
@ -2427,12 +2430,11 @@ buf_LRU_free_one_page(
|
|||
rw_lock_x_lock(hash_lock);
|
||||
mutex_enter(block_mutex);
|
||||
|
||||
if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
|
||||
!= BUF_BLOCK_ZIP_FREE) {
|
||||
if (buf_LRU_block_remove_hashed(bpage, true)) {
|
||||
buf_LRU_block_free_hashed_page((buf_block_t*) bpage);
|
||||
}
|
||||
|
||||
/* buf_LRU_block_remove_hashed_page() releases hash_lock and block_mutex */
|
||||
/* buf_LRU_block_remove_hashed() releases hash_lock and block_mutex */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(!rw_lock_own(hash_lock, RW_LOCK_EX)
|
||||
&& !rw_lock_own(hash_lock, RW_LOCK_SHARED));
|
||||
|
|
@ -2606,7 +2608,7 @@ buf_LRU_validate_instance(
|
|||
bpage = UT_LIST_GET_NEXT(LRU, bpage)) {
|
||||
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -107,7 +107,7 @@ buf_read_page_low(
|
|||
dberr_t* err, /*!< out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
|
||||
trying to read from a non-existent tablespace, or a
|
||||
tablespace which is just now being dropped */
|
||||
ibool sync, /*!< in: TRUE if synchronous aio is desired */
|
||||
bool sync, /*!< in: true if synchronous aio is desired */
|
||||
ulint mode, /*!< in: BUF_READ_IBUF_PAGES_ONLY, ...,
|
||||
ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
|
||||
at read-ahead functions) */
|
||||
|
|
@ -152,7 +152,7 @@ buf_read_page_low(
|
|||
syncronous i/o, to make sure they do not get involved in
|
||||
thread deadlocks. */
|
||||
|
||||
sync = TRUE;
|
||||
sync = true;
|
||||
}
|
||||
|
||||
/* The following call will also check if the tablespace does not exist
|
||||
|
|
@ -169,15 +169,17 @@ buf_read_page_low(
|
|||
#ifdef UNIV_DEBUG
|
||||
if (buf_debug_prints) {
|
||||
fprintf(stderr,
|
||||
"Posting read request for page %lu, sync %lu\n",
|
||||
(ulong) offset,
|
||||
(ulong) sync);
|
||||
"Posting read request for page %lu, sync %s\n",
|
||||
(ulong) offset, sync ? "true" : "false");
|
||||
}
|
||||
#endif
|
||||
|
||||
ut_ad(buf_page_in_file(bpage));
|
||||
|
||||
if (sync) {
|
||||
thd_wait_begin(NULL, THD_WAIT_DISKIO);
|
||||
}
|
||||
|
||||
if (zip_size) {
|
||||
*err = fil_io(OS_FILE_READ | wake_later
|
||||
| ignore_nonexistent_pages,
|
||||
|
|
@ -191,7 +193,10 @@ buf_read_page_low(
|
|||
sync, space, 0, offset, 0, UNIV_PAGE_SIZE,
|
||||
((buf_block_t*) bpage)->frame, bpage);
|
||||
}
|
||||
|
||||
if (sync) {
|
||||
thd_wait_end(NULL);
|
||||
}
|
||||
|
||||
if (*err != DB_SUCCESS) {
|
||||
if (ignore_nonexistent_pages || *err == DB_TABLESPACE_DELETED) {
|
||||
|
|
@ -337,7 +342,7 @@ read_ahead:
|
|||
|
||||
if (!ibuf_bitmap_page(zip_size, i)) {
|
||||
count += buf_read_page_low(
|
||||
&err, FALSE,
|
||||
&err, false,
|
||||
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
|
||||
space, zip_size, FALSE,
|
||||
tablespace_version, i);
|
||||
|
|
@ -401,7 +406,7 @@ buf_read_page(
|
|||
/* We do the i/o in the synchronous aio mode to save thread
|
||||
switches: hence TRUE */
|
||||
|
||||
count = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
|
||||
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
|
||||
zip_size, FALSE,
|
||||
tablespace_version, offset);
|
||||
srv_stats.buf_pool_reads.add(count);
|
||||
|
|
@ -447,7 +452,7 @@ buf_read_page_async(
|
|||
|
||||
tablespace_version = fil_space_get_version(space);
|
||||
|
||||
count = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE
|
||||
count = buf_read_page_low(&err, true, BUF_READ_ANY_PAGE
|
||||
| OS_AIO_SIMULATED_WAKE_LATER
|
||||
| BUF_READ_IGNORE_NONEXISTENT_PAGES,
|
||||
space, zip_size, FALSE,
|
||||
|
|
@ -708,7 +713,7 @@ buf_read_ahead_linear(
|
|||
|
||||
if (!ibuf_bitmap_page(zip_size, i)) {
|
||||
count += buf_read_page_low(
|
||||
&err, FALSE,
|
||||
&err, false,
|
||||
ibuf_mode,
|
||||
space, zip_size, FALSE, tablespace_version, i);
|
||||
if (err == DB_TABLESPACE_DELETED) {
|
||||
|
|
@ -754,7 +759,7 @@ UNIV_INTERN
|
|||
void
|
||||
buf_read_ibuf_merge_pages(
|
||||
/*======================*/
|
||||
ibool sync, /*!< in: TRUE if the caller
|
||||
bool sync, /*!< in: true if the caller
|
||||
wants this function to wait
|
||||
for the highest address page
|
||||
to get read in, before this
|
||||
|
|
@ -893,11 +898,11 @@ buf_read_recv_pages(
|
|||
os_aio_print_debug = FALSE;
|
||||
|
||||
if ((i + 1 == n_stored) && sync) {
|
||||
buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
|
||||
buf_read_page_low(&err, true, BUF_READ_ANY_PAGE, space,
|
||||
zip_size, TRUE, tablespace_version,
|
||||
page_nos[i]);
|
||||
} else {
|
||||
buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE
|
||||
buf_read_page_low(&err, false, BUF_READ_ANY_PAGE
|
||||
| OS_AIO_SIMULATED_WAKE_LATER,
|
||||
space, zip_size, TRUE,
|
||||
tablespace_version, page_nos[i]);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
#!/bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||
# Copyright (c) 2006, 2013, 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
|
||||
|
|
|
|||
|
|
@ -32,7 +32,6 @@ Created 4/18/1996 Heikki Tuuri
|
|||
#include "dict0crea.h"
|
||||
#include "btr0btr.h"
|
||||
#include "dict0load.h"
|
||||
#include "dict0load.h"
|
||||
#include "trx0trx.h"
|
||||
#include "srv0srv.h"
|
||||
#include "ibuf0ibuf.h"
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ Created 1/8/1996 Heikki Tuuri
|
|||
#include "ut0vec.h"
|
||||
#include "dict0priv.h"
|
||||
#include "fts0priv.h"
|
||||
#include "ha_prototypes.h"
|
||||
|
||||
/*****************************************************************//**
|
||||
Based on a table object, this function builds the entry to be inserted
|
||||
|
|
@ -891,13 +892,17 @@ create:
|
|||
for (index = UT_LIST_GET_FIRST(table->indexes);
|
||||
index;
|
||||
index = UT_LIST_GET_NEXT(indexes, index)) {
|
||||
if (index->id == index_id && !(index->type & DICT_FTS)) {
|
||||
if (index->id == index_id) {
|
||||
if (index->type & DICT_FTS) {
|
||||
return(FIL_NULL);
|
||||
} else {
|
||||
root_page_no = btr_create(type, space, zip_size,
|
||||
index_id, index, mtr);
|
||||
index->page = (unsigned int) root_page_no;
|
||||
return(root_page_no);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
|
|
@ -1453,11 +1458,11 @@ static __attribute__((nonnull, warn_unused_result))
|
|||
dberr_t
|
||||
dict_foreign_eval_sql(
|
||||
/*==================*/
|
||||
pars_info_t* info, /*!< in: info struct, or NULL */
|
||||
pars_info_t* info, /*!< in: info struct */
|
||||
const char* sql, /*!< in: SQL string to evaluate */
|
||||
dict_table_t* table, /*!< in: table */
|
||||
dict_foreign_t* foreign,/*!< in: foreign */
|
||||
trx_t* trx) /*!< in: transaction */
|
||||
const char* name, /*!< in: table name (for diagnostics) */
|
||||
const char* id, /*!< in: foreign key id */
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
{
|
||||
dberr_t error;
|
||||
FILE* ef = dict_foreign_err_file;
|
||||
|
|
@ -1470,9 +1475,9 @@ dict_foreign_eval_sql(
|
|||
ut_print_timestamp(ef);
|
||||
fputs(" Error in foreign key constraint creation for table ",
|
||||
ef);
|
||||
ut_print_name(ef, trx, TRUE, table->name);
|
||||
ut_print_name(ef, trx, TRUE, name);
|
||||
fputs(".\nA foreign key constraint of name ", ef);
|
||||
ut_print_name(ef, trx, TRUE, foreign->id);
|
||||
ut_print_name(ef, trx, TRUE, id);
|
||||
fputs("\nalready exists."
|
||||
" (Note that internally InnoDB adds 'databasename'\n"
|
||||
"in front of the user-defined constraint name.)\n"
|
||||
|
|
@ -1499,7 +1504,7 @@ dict_foreign_eval_sql(
|
|||
ut_print_timestamp(ef);
|
||||
fputs(" Internal error in foreign key constraint creation"
|
||||
" for table ", ef);
|
||||
ut_print_name(ef, trx, TRUE, table->name);
|
||||
ut_print_name(ef, trx, TRUE, name);
|
||||
fputs(".\n"
|
||||
"See the MySQL .err log in the datadir"
|
||||
" for more information.\n", ef);
|
||||
|
|
@ -1519,10 +1524,10 @@ static __attribute__((nonnull, warn_unused_result))
|
|||
dberr_t
|
||||
dict_create_add_foreign_field_to_dictionary(
|
||||
/*========================================*/
|
||||
ulint field_nr, /*!< in: foreign field number */
|
||||
dict_table_t* table, /*!< in: table */
|
||||
dict_foreign_t* foreign, /*!< in: foreign */
|
||||
trx_t* trx) /*!< in: transaction */
|
||||
ulint field_nr, /*!< in: field number */
|
||||
const char* table_name, /*!< in: table name */
|
||||
const dict_foreign_t* foreign, /*!< in: foreign */
|
||||
trx_t* trx) /*!< in/out: transaction */
|
||||
{
|
||||
pars_info_t* info = pars_info_create();
|
||||
|
||||
|
|
@ -1543,48 +1548,26 @@ dict_create_add_foreign_field_to_dictionary(
|
|||
"INSERT INTO SYS_FOREIGN_COLS VALUES"
|
||||
"(:id, :pos, :for_col_name, :ref_col_name);\n"
|
||||
"END;\n",
|
||||
table, foreign, trx));
|
||||
table_name, foreign->id, trx));
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Add a single foreign key definition to the data dictionary tables in the
|
||||
database. We also generate names to constraints that were not named by the
|
||||
user. A generated constraint has a name of the format
|
||||
databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and
|
||||
are given locally for this table, that is, the number is not global, as in
|
||||
the old format constraints < 4.0.18 it used to be.
|
||||
Add a foreign key definition to the data dictionary tables.
|
||||
@return error code or DB_SUCCESS */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
dict_create_add_foreign_to_dictionary(
|
||||
/*==================================*/
|
||||
ulint* id_nr, /*!< in/out: number to use in id generation;
|
||||
incremented if used */
|
||||
dict_table_t* table, /*!< in: table */
|
||||
dict_foreign_t* foreign,/*!< in: foreign */
|
||||
const char* name, /*!< in: table name */
|
||||
const dict_foreign_t* foreign,/*!< in: foreign key */
|
||||
trx_t* trx) /*!< in/out: dictionary transaction */
|
||||
{
|
||||
dberr_t error;
|
||||
ulint i;
|
||||
|
||||
pars_info_t* info = pars_info_create();
|
||||
|
||||
if (foreign->id == NULL) {
|
||||
/* Generate a new constraint id */
|
||||
char* id;
|
||||
ulint namelen = strlen(table->name);
|
||||
|
||||
id = static_cast<char*>(mem_heap_alloc(
|
||||
foreign->heap, namelen + 20));
|
||||
|
||||
/* no overflow if number < 1e13 */
|
||||
sprintf(id, "%s_ibfk_%lu", table->name, (ulong) (*id_nr)++);
|
||||
foreign->id = id;
|
||||
}
|
||||
|
||||
pars_info_add_str_literal(info, "id", foreign->id);
|
||||
|
||||
pars_info_add_str_literal(info, "for_name", table->name);
|
||||
pars_info_add_str_literal(info, "for_name", name);
|
||||
|
||||
pars_info_add_str_literal(info, "ref_name",
|
||||
foreign->referenced_table_name);
|
||||
|
|
@ -1598,16 +1581,16 @@ dict_create_add_foreign_to_dictionary(
|
|||
"INSERT INTO SYS_FOREIGN VALUES"
|
||||
"(:id, :for_name, :ref_name, :n_cols);\n"
|
||||
"END;\n"
|
||||
, table, foreign, trx);
|
||||
, name, foreign->id, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
for (i = 0; i < foreign->n_fields; i++) {
|
||||
for (ulint i = 0; i < foreign->n_fields; i++) {
|
||||
error = dict_create_add_foreign_field_to_dictionary(
|
||||
i, table, foreign, trx);
|
||||
i, name, foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
|
|
@ -1654,7 +1637,15 @@ dict_create_add_foreigns_to_dictionary(
|
|||
foreign;
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
|
||||
|
||||
error = dict_create_add_foreign_to_dictionary(&number, table,
|
||||
error = dict_create_add_foreign_id(&number, table->name,
|
||||
foreign);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
||||
error = dict_create_add_foreign_to_dictionary(table->name,
|
||||
foreign, trx);
|
||||
|
||||
if (error != DB_SUCCESS) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
@ -413,7 +413,8 @@ dict_table_try_drop_aborted(
|
|||
trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
|
||||
|
||||
if (table == NULL) {
|
||||
table = dict_table_open_on_id_low(table_id);
|
||||
table = dict_table_open_on_id_low(
|
||||
table_id, DICT_ERR_IGNORE_NONE);
|
||||
} else {
|
||||
ut_ad(table->id == table_id);
|
||||
}
|
||||
|
|
@ -786,9 +787,7 @@ dict_table_open_on_id(
|
|||
/*==================*/
|
||||
table_id_t table_id, /*!< in: table id */
|
||||
ibool dict_locked, /*!< in: TRUE=data dictionary locked */
|
||||
ibool try_drop) /*!< in: TRUE=try to drop any orphan
|
||||
indexes after an aborted online
|
||||
index creation */
|
||||
dict_table_op_t table_op) /*!< in: operation to perform */
|
||||
{
|
||||
dict_table_t* table;
|
||||
|
||||
|
|
@ -798,7 +797,11 @@ dict_table_open_on_id(
|
|||
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
table = dict_table_open_on_id_low(table_id);
|
||||
table = dict_table_open_on_id_low(
|
||||
table_id,
|
||||
table_op == DICT_TABLE_OP_LOAD_TABLESPACE
|
||||
? DICT_ERR_IGNORE_RECOVER_LOCK
|
||||
: DICT_ERR_IGNORE_NONE);
|
||||
|
||||
if (table != NULL) {
|
||||
|
||||
|
|
@ -812,7 +815,8 @@ dict_table_open_on_id(
|
|||
}
|
||||
|
||||
if (!dict_locked) {
|
||||
dict_table_try_drop_aborted_and_mutex_exit(table, try_drop);
|
||||
dict_table_try_drop_aborted_and_mutex_exit(
|
||||
table, table_op == DICT_TABLE_OP_DROP_ORPHAN);
|
||||
}
|
||||
|
||||
return(table);
|
||||
|
|
@ -1459,12 +1463,13 @@ dict_table_rename_in_cache(
|
|||
filepath = fil_make_ibd_name(table->name, false);
|
||||
}
|
||||
|
||||
fil_delete_tablespace(table->space, BUF_REMOVE_FLUSH_NO_WRITE);
|
||||
fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE);
|
||||
|
||||
/* Delete any temp file hanging around. */
|
||||
if (os_file_status(filepath, &exists, &type)
|
||||
&& exists
|
||||
&& !os_file_delete_if_exists(filepath)) {
|
||||
&& !os_file_delete_if_exists(innodb_file_temp_key,
|
||||
filepath)) {
|
||||
|
||||
ib_logf(IB_LOG_LEVEL_INFO,
|
||||
"Delete of %s failed.", filepath);
|
||||
|
|
@ -1606,22 +1611,78 @@ dict_table_rename_in_cache(
|
|||
dict_mem_foreign_table_name_lookup_set(foreign, FALSE);
|
||||
}
|
||||
if (strchr(foreign->id, '/')) {
|
||||
/* This is a >= 4.0.18 format id */
|
||||
|
||||
ulint db_len;
|
||||
char* old_id;
|
||||
char old_name_cs_filename[MAX_TABLE_NAME_LEN+20];
|
||||
uint errors = 0;
|
||||
|
||||
/* This is a >= 4.0.18 format id */
|
||||
/* All table names are internally stored in charset
|
||||
my_charset_filename (except the temp tables and the
|
||||
partition identifier suffix in partition tables). The
|
||||
foreign key constraint names are internally stored
|
||||
in UTF-8 charset. The variable fkid here is used
|
||||
to store foreign key constraint name in charset
|
||||
my_charset_filename for comparison further below. */
|
||||
char fkid[MAX_TABLE_NAME_LEN+20];
|
||||
ibool on_tmp = FALSE;
|
||||
|
||||
/* The old table name in my_charset_filename is stored
|
||||
in old_name_cs_filename */
|
||||
|
||||
strncpy(old_name_cs_filename, old_name,
|
||||
MAX_TABLE_NAME_LEN);
|
||||
if (strstr(old_name, TEMP_TABLE_PATH_PREFIX) == NULL) {
|
||||
|
||||
innobase_convert_to_system_charset(
|
||||
strchr(old_name_cs_filename, '/') + 1,
|
||||
strchr(old_name, '/') + 1,
|
||||
MAX_TABLE_NAME_LEN, &errors);
|
||||
|
||||
if (errors) {
|
||||
/* There has been an error to convert
|
||||
old table into UTF-8. This probably
|
||||
means that the old table name is
|
||||
actually in UTF-8. */
|
||||
innobase_convert_to_filename_charset(
|
||||
strchr(old_name_cs_filename,
|
||||
'/') + 1,
|
||||
strchr(old_name, '/') + 1,
|
||||
MAX_TABLE_NAME_LEN);
|
||||
} else {
|
||||
/* Old name already in
|
||||
my_charset_filename */
|
||||
strncpy(old_name_cs_filename, old_name,
|
||||
MAX_TABLE_NAME_LEN);
|
||||
}
|
||||
}
|
||||
|
||||
strncpy(fkid, foreign->id, MAX_TABLE_NAME_LEN);
|
||||
|
||||
if (strstr(fkid, TEMP_TABLE_PATH_PREFIX) == NULL) {
|
||||
innobase_convert_to_filename_charset(
|
||||
strchr(fkid, '/') + 1,
|
||||
strchr(foreign->id, '/') + 1,
|
||||
MAX_TABLE_NAME_LEN+20);
|
||||
} else {
|
||||
on_tmp = TRUE;
|
||||
}
|
||||
|
||||
old_id = mem_strdup(foreign->id);
|
||||
|
||||
if (ut_strlen(foreign->id) > ut_strlen(old_name)
|
||||
if (ut_strlen(fkid) > ut_strlen(old_name_cs_filename)
|
||||
+ ((sizeof dict_ibfk) - 1)
|
||||
&& !memcmp(foreign->id, old_name,
|
||||
ut_strlen(old_name))
|
||||
&& !memcmp(foreign->id + ut_strlen(old_name),
|
||||
&& !memcmp(fkid, old_name_cs_filename,
|
||||
ut_strlen(old_name_cs_filename))
|
||||
&& !memcmp(fkid + ut_strlen(old_name_cs_filename),
|
||||
dict_ibfk, (sizeof dict_ibfk) - 1)) {
|
||||
|
||||
/* This is a generated >= 4.0.18 format id */
|
||||
|
||||
char table_name[MAX_TABLE_NAME_LEN] = "";
|
||||
uint errors = 0;
|
||||
|
||||
if (strlen(table->name) > strlen(old_name)) {
|
||||
foreign->id = static_cast<char*>(
|
||||
mem_heap_alloc(
|
||||
|
|
@ -1630,11 +1691,36 @@ dict_table_rename_in_cache(
|
|||
+ strlen(old_id) + 1));
|
||||
}
|
||||
|
||||
/* Convert the table name to UTF-8 */
|
||||
strncpy(table_name, table->name,
|
||||
MAX_TABLE_NAME_LEN);
|
||||
innobase_convert_to_system_charset(
|
||||
strchr(table_name, '/') + 1,
|
||||
strchr(table->name, '/') + 1,
|
||||
MAX_TABLE_NAME_LEN, &errors);
|
||||
|
||||
if (errors) {
|
||||
/* Table name could not be converted
|
||||
from charset my_charset_filename to
|
||||
UTF-8. This means that the table name
|
||||
is already in UTF-8 (#mysql#50). */
|
||||
strncpy(table_name, table->name,
|
||||
MAX_TABLE_NAME_LEN);
|
||||
}
|
||||
|
||||
/* Replace the prefix 'databasename/tablename'
|
||||
with the new names */
|
||||
strcpy(foreign->id, table->name);
|
||||
strcpy(foreign->id, table_name);
|
||||
if (on_tmp) {
|
||||
strcat(foreign->id,
|
||||
old_id + ut_strlen(old_name));
|
||||
} else {
|
||||
sprintf(strchr(foreign->id, '/') + 1,
|
||||
"%s%s",
|
||||
strchr(table_name, '/') +1,
|
||||
strstr(old_id, "_ibfk_") );
|
||||
}
|
||||
|
||||
} else {
|
||||
/* This is a >= 4.0.18 format id where the user
|
||||
gave the id name */
|
||||
|
|
@ -2033,6 +2119,10 @@ dict_index_too_big_for_tree(
|
|||
return(false);
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF(
|
||||
"ib_force_create_table",
|
||||
return(FALSE););
|
||||
|
||||
comp = dict_table_is_comp(table);
|
||||
zip_size = dict_table_zip_size(table);
|
||||
|
||||
|
|
@ -2047,7 +2137,10 @@ dict_index_too_big_for_tree(
|
|||
number in the page modification log. The maximum
|
||||
allowed node pointer size is half that. */
|
||||
page_rec_max = page_zip_empty_size(new_index->n_fields,
|
||||
zip_size) - 1;
|
||||
zip_size);
|
||||
if (page_rec_max) {
|
||||
page_rec_max--;
|
||||
}
|
||||
page_ptr_max = page_rec_max / 2;
|
||||
/* On a compressed page, there is a two-byte entry in
|
||||
the dense page directory for every record. But there
|
||||
|
|
@ -3117,13 +3210,16 @@ dict_index_t*
|
|||
dict_foreign_find_index(
|
||||
/*====================*/
|
||||
const dict_table_t* table, /*!< in: table */
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
const char** columns,/*!< in: array of column names */
|
||||
ulint n_cols, /*!< in: number of columns */
|
||||
const dict_index_t* types_idx,
|
||||
/*!< in: NULL or an index
|
||||
whose types the column types
|
||||
must match */
|
||||
ibool check_charsets,
|
||||
bool check_charsets,
|
||||
/*!< in: whether to check
|
||||
charsets. only has an effect
|
||||
if types_idx != NULL */
|
||||
|
|
@ -3139,20 +3235,16 @@ dict_foreign_find_index(
|
|||
index = dict_table_get_first_index(table);
|
||||
|
||||
while (index != NULL) {
|
||||
/* Ignore matches that refer to the same instance
|
||||
(or the index is to be dropped) */
|
||||
if (types_idx == index || index->type & DICT_FTS
|
||||
|| index->to_be_dropped) {
|
||||
|
||||
goto next_rec;
|
||||
|
||||
} else if (dict_foreign_qualify_index(
|
||||
table, columns, n_cols, index, types_idx,
|
||||
if (types_idx != index
|
||||
&& !(index->type & DICT_FTS)
|
||||
&& !index->to_be_dropped
|
||||
&& dict_foreign_qualify_index(
|
||||
table, col_names, columns, n_cols,
|
||||
index, types_idx,
|
||||
check_charsets, check_null)) {
|
||||
return(index);
|
||||
}
|
||||
|
||||
next_rec:
|
||||
index = dict_table_get_next_index(index);
|
||||
}
|
||||
|
||||
|
|
@ -3211,9 +3303,16 @@ UNIV_INTERN
|
|||
dberr_t
|
||||
dict_foreign_add_to_cache(
|
||||
/*======================*/
|
||||
dict_foreign_t* foreign, /*!< in, own: foreign key constraint */
|
||||
ibool check_charsets) /*!< in: TRUE=check charset
|
||||
dict_foreign_t* foreign,
|
||||
/*!< in, own: foreign key constraint */
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL to use
|
||||
foreign->foreign_table->col_names */
|
||||
bool check_charsets,
|
||||
/*!< in: whether to check charset
|
||||
compatibility */
|
||||
dict_err_ignore_t ignore_err)
|
||||
/*!< in: error to be ignored */
|
||||
{
|
||||
dict_table_t* for_table;
|
||||
dict_table_t* ref_table;
|
||||
|
|
@ -3246,14 +3345,15 @@ dict_foreign_add_to_cache(
|
|||
for_in_cache = foreign;
|
||||
}
|
||||
|
||||
if (for_in_cache->referenced_table == NULL && ref_table) {
|
||||
if (ref_table && !for_in_cache->referenced_table) {
|
||||
index = dict_foreign_find_index(
|
||||
ref_table,
|
||||
ref_table, NULL,
|
||||
for_in_cache->referenced_col_names,
|
||||
for_in_cache->n_fields, for_in_cache->foreign_index,
|
||||
check_charsets, FALSE);
|
||||
check_charsets, false);
|
||||
|
||||
if (index == NULL) {
|
||||
if (index == NULL
|
||||
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
||||
dict_foreign_error_report(
|
||||
ef, for_in_cache,
|
||||
"there is no index in referenced table"
|
||||
|
|
@ -3278,9 +3378,9 @@ dict_foreign_add_to_cache(
|
|||
added_to_referenced_list = TRUE;
|
||||
}
|
||||
|
||||
if (for_in_cache->foreign_table == NULL && for_table) {
|
||||
if (for_table && !for_in_cache->foreign_table) {
|
||||
index = dict_foreign_find_index(
|
||||
for_table,
|
||||
for_table, col_names,
|
||||
for_in_cache->foreign_col_names,
|
||||
for_in_cache->n_fields,
|
||||
for_in_cache->referenced_index, check_charsets,
|
||||
|
|
@ -3288,7 +3388,8 @@ dict_foreign_add_to_cache(
|
|||
& (DICT_FOREIGN_ON_DELETE_SET_NULL
|
||||
| DICT_FOREIGN_ON_UPDATE_SET_NULL));
|
||||
|
||||
if (index == NULL) {
|
||||
if (index == NULL
|
||||
&& !(ignore_err & DICT_ERR_IGNORE_FK_NOKEY)) {
|
||||
dict_foreign_error_report(
|
||||
ef, for_in_cache,
|
||||
"there is no index in the table"
|
||||
|
|
@ -3350,14 +3451,27 @@ dict_scan_to(
|
|||
const char* string) /*!< in: look for this */
|
||||
{
|
||||
char quote = '\0';
|
||||
bool escape = false;
|
||||
|
||||
for (; *ptr; ptr++) {
|
||||
if (*ptr == quote) {
|
||||
/* Closing quote character: do not look for
|
||||
starting quote or the keyword. */
|
||||
|
||||
/* If the quote character is escaped by a
|
||||
backslash, ignore it. */
|
||||
if (escape) {
|
||||
escape = false;
|
||||
} else {
|
||||
quote = '\0';
|
||||
}
|
||||
} else if (quote) {
|
||||
/* Within quotes: do nothing. */
|
||||
if (escape) {
|
||||
escape = false;
|
||||
} else if (*ptr == '\\') {
|
||||
escape = true;
|
||||
}
|
||||
} else if (*ptr == '`' || *ptr == '"' || *ptr == '\'') {
|
||||
/* Starting quote: remember the quote character. */
|
||||
quote = *ptr;
|
||||
|
|
@ -3772,6 +3886,11 @@ dict_strip_comments(
|
|||
char* ptr;
|
||||
/* unclosed quote character (0 if none) */
|
||||
char quote = 0;
|
||||
bool escape = false;
|
||||
|
||||
DBUG_ENTER("dict_strip_comments");
|
||||
|
||||
DBUG_PRINT("dict_strip_comments", ("%s", sql_string));
|
||||
|
||||
str = static_cast<char*>(mem_alloc(sql_length + 1));
|
||||
|
||||
|
|
@ -3786,16 +3905,29 @@ end_of_string:
|
|||
|
||||
ut_a(ptr <= str + sql_length);
|
||||
|
||||
return(str);
|
||||
DBUG_PRINT("dict_strip_comments", ("%s", str));
|
||||
DBUG_RETURN(str);
|
||||
}
|
||||
|
||||
if (*sptr == quote) {
|
||||
/* Closing quote character: do not look for
|
||||
starting quote or comments. */
|
||||
|
||||
/* If the quote character is escaped by a
|
||||
backslash, ignore it. */
|
||||
if (escape) {
|
||||
escape = false;
|
||||
} else {
|
||||
quote = 0;
|
||||
}
|
||||
} else if (quote) {
|
||||
/* Within quotes: do not look for
|
||||
starting quotes or comments. */
|
||||
if (escape) {
|
||||
escape = false;
|
||||
} else if (*sptr == '\\') {
|
||||
escape = true;
|
||||
}
|
||||
} else if (*sptr == '"' || *sptr == '`' || *sptr == '\'') {
|
||||
/* Starting quote: remember the quote character. */
|
||||
quote = *sptr;
|
||||
|
|
@ -4164,10 +4296,13 @@ col_loop1:
|
|||
}
|
||||
|
||||
/* Try to find an index which contains the columns
|
||||
as the first fields and in the right order */
|
||||
as the first fields and in the right order. There is
|
||||
no need to check column type match (on types_idx), since
|
||||
the referenced table can be NULL if foreign_key_checks is
|
||||
set to 0 */
|
||||
|
||||
index = dict_foreign_find_index(table, column_names, i,
|
||||
NULL, TRUE, FALSE);
|
||||
index = dict_foreign_find_index(
|
||||
table, NULL, column_names, i, NULL, TRUE, FALSE);
|
||||
|
||||
if (!index) {
|
||||
mutex_enter(&dict_foreign_err_mutex);
|
||||
|
|
@ -4439,7 +4574,7 @@ try_find_index:
|
|||
foreign->foreign_index */
|
||||
|
||||
if (referenced_table) {
|
||||
index = dict_foreign_find_index(referenced_table,
|
||||
index = dict_foreign_find_index(referenced_table, NULL,
|
||||
column_names, i,
|
||||
foreign->foreign_index,
|
||||
TRUE, FALSE);
|
||||
|
|
@ -5635,38 +5770,42 @@ dict_table_get_index_on_name(
|
|||
|
||||
/**********************************************************************//**
|
||||
Replace the index passed in with another equivalent index in the
|
||||
foreign key lists of the table. */
|
||||
foreign key lists of the table.
|
||||
@return whether all replacements were found */
|
||||
UNIV_INTERN
|
||||
void
|
||||
bool
|
||||
dict_foreign_replace_index(
|
||||
/*=======================*/
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
const dict_index_t* index, /*!< in: index to be replaced */
|
||||
const trx_t* trx) /*!< in: transaction handle */
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
const dict_index_t* index) /*!< in: index to be replaced */
|
||||
{
|
||||
bool found = true;
|
||||
dict_foreign_t* foreign;
|
||||
|
||||
ut_ad(index->to_be_dropped);
|
||||
ut_ad(index->table == table);
|
||||
|
||||
for (foreign = UT_LIST_GET_FIRST(table->foreign_list);
|
||||
foreign;
|
||||
foreign = UT_LIST_GET_NEXT(foreign_list, foreign)) {
|
||||
|
||||
dict_index_t* new_index;
|
||||
|
||||
if (foreign->foreign_index == index) {
|
||||
ut_ad(foreign->foreign_table == index->table);
|
||||
|
||||
new_index = dict_foreign_find_index(
|
||||
foreign->foreign_table,
|
||||
dict_index_t* new_index = dict_foreign_find_index(
|
||||
foreign->foreign_table, col_names,
|
||||
foreign->foreign_col_names,
|
||||
foreign->n_fields, index,
|
||||
/*check_charsets=*/TRUE, /*check_null=*/FALSE);
|
||||
/* There must exist an alternative index,
|
||||
since this must have been checked earlier. */
|
||||
ut_a(new_index || !trx->check_foreigns);
|
||||
ut_ad(!new_index || new_index->table == index->table);
|
||||
ut_ad(!new_index || !new_index->to_be_dropped);
|
||||
if (new_index) {
|
||||
ut_ad(new_index->table == index->table);
|
||||
ut_ad(!new_index->to_be_dropped);
|
||||
} else {
|
||||
found = false;
|
||||
}
|
||||
|
||||
foreign->foreign_index = new_index;
|
||||
}
|
||||
|
|
@ -5676,25 +5815,28 @@ dict_foreign_replace_index(
|
|||
foreign;
|
||||
foreign = UT_LIST_GET_NEXT(referenced_list, foreign)) {
|
||||
|
||||
dict_index_t* new_index;
|
||||
|
||||
if (foreign->referenced_index == index) {
|
||||
ut_ad(foreign->referenced_table == index->table);
|
||||
|
||||
new_index = dict_foreign_find_index(
|
||||
foreign->referenced_table,
|
||||
dict_index_t* new_index = dict_foreign_find_index(
|
||||
foreign->referenced_table, NULL,
|
||||
foreign->referenced_col_names,
|
||||
foreign->n_fields, index,
|
||||
/*check_charsets=*/TRUE, /*check_null=*/FALSE);
|
||||
/* There must exist an alternative index,
|
||||
since this must have been checked earlier. */
|
||||
ut_a(new_index || !trx->check_foreigns);
|
||||
ut_ad(!new_index || new_index->table == index->table);
|
||||
ut_ad(!new_index || !new_index->to_be_dropped);
|
||||
if (new_index) {
|
||||
ut_ad(new_index->table == index->table);
|
||||
ut_ad(!new_index->to_be_dropped);
|
||||
} else {
|
||||
found = false;
|
||||
}
|
||||
|
||||
foreign->referenced_index = new_index;
|
||||
}
|
||||
}
|
||||
|
||||
return(found);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
@ -6118,7 +6260,7 @@ dict_close(void)
|
|||
}
|
||||
}
|
||||
|
||||
# ifdef UNIV_DEBUG
|
||||
#ifdef UNIV_DEBUG
|
||||
/**********************************************************************//**
|
||||
Validate the dictionary table LRU list.
|
||||
@return TRUE if valid */
|
||||
|
|
@ -6203,7 +6345,7 @@ dict_non_lru_find_table(
|
|||
|
||||
return(FALSE);
|
||||
}
|
||||
# endif /* UNIV_DEBUG */
|
||||
#endif /* UNIV_DEBUG */
|
||||
/*********************************************************************//**
|
||||
Check an index to see whether its first fields are the columns in the array,
|
||||
in the same order and is not marked for deletion and is not the same
|
||||
|
|
@ -6214,6 +6356,9 @@ bool
|
|||
dict_foreign_qualify_index(
|
||||
/*=======================*/
|
||||
const dict_table_t* table, /*!< in: table */
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
const char** columns,/*!< in: array of column names */
|
||||
ulint n_cols, /*!< in: number of columns */
|
||||
const dict_index_t* index, /*!< in: index to check */
|
||||
|
|
@ -6221,7 +6366,7 @@ dict_foreign_qualify_index(
|
|||
/*!< in: NULL or an index
|
||||
whose types the column types
|
||||
must match */
|
||||
ibool check_charsets,
|
||||
bool check_charsets,
|
||||
/*!< in: whether to check
|
||||
charsets. only has an effect
|
||||
if types_idx != NULL */
|
||||
|
|
@ -6230,50 +6375,46 @@ dict_foreign_qualify_index(
|
|||
the columns must be declared
|
||||
NOT NULL */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
if (dict_index_get_n_fields(index) < n_cols) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
for (i= 0; i < n_cols; i++) {
|
||||
for (ulint i = 0; i < n_cols; i++) {
|
||||
dict_field_t* field;
|
||||
const char* col_name;
|
||||
ulint col_no;
|
||||
|
||||
field = dict_index_get_nth_field(index, i);
|
||||
|
||||
col_name = dict_table_get_col_name(
|
||||
table, dict_col_get_no(field->col));
|
||||
col_no = dict_col_get_no(field->col);
|
||||
|
||||
if (field->prefix_len != 0) {
|
||||
/* We do not accept column prefix
|
||||
indexes here */
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (0 != innobase_strcasecmp(columns[i],
|
||||
col_name)) {
|
||||
break;
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (check_null
|
||||
&& (field->col->prtype & DATA_NOT_NULL)) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
break;
|
||||
col_name = col_names
|
||||
? col_names[col_no]
|
||||
: dict_table_get_col_name(table, col_no);
|
||||
|
||||
if (0 != innobase_strcasecmp(columns[i], col_name)) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
if (types_idx && !cmp_cols_are_equal(
|
||||
dict_index_get_nth_col(index, i),
|
||||
dict_index_get_nth_col(types_idx,
|
||||
i),
|
||||
dict_index_get_nth_col(types_idx, i),
|
||||
check_charsets)) {
|
||||
|
||||
break;
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
return((i == n_cols) ? true : false);
|
||||
return(true);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -960,7 +960,7 @@ UNIV_INTERN
|
|||
void
|
||||
dict_check_tablespaces_and_store_max_id(
|
||||
/*====================================*/
|
||||
ibool in_crash_recovery) /*!< in: are we doing a crash recovery */
|
||||
dict_check_t dict_check) /*!< in: how to check */
|
||||
{
|
||||
dict_table_t* sys_tables;
|
||||
dict_index_t* sys_index;
|
||||
|
|
@ -1039,7 +1039,7 @@ loop:
|
|||
ib_logf(IB_LOG_LEVEL_ERROR,
|
||||
"Table '%s' in InnoDB data dictionary"
|
||||
" has unknown type %lx", table_name, flags);
|
||||
|
||||
mem_free(name);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
|
|
@ -1085,15 +1085,36 @@ loop:
|
|||
if (space_id == 0) {
|
||||
/* The system tablespace always exists. */
|
||||
ut_ad(!discarded);
|
||||
} else if (in_crash_recovery) {
|
||||
goto next_tablespace;
|
||||
}
|
||||
|
||||
switch (dict_check) {
|
||||
case DICT_CHECK_ALL_LOADED:
|
||||
/* All tablespaces should have been found in
|
||||
fil_load_single_table_tablespaces(). */
|
||||
|
||||
fil_space_for_table_exists_in_mem(
|
||||
space_id, name, TRUE, !(is_temp || discarded),
|
||||
false, NULL, 0);
|
||||
break;
|
||||
|
||||
} else if (!discarded) {
|
||||
case DICT_CHECK_SOME_LOADED:
|
||||
/* Some tablespaces may have been opened in
|
||||
trx_resurrect_table_locks(). */
|
||||
if (fil_space_for_table_exists_in_mem(
|
||||
space_id, name, FALSE, FALSE,
|
||||
false, NULL, 0)) {
|
||||
break;
|
||||
}
|
||||
/* fall through */
|
||||
case DICT_CHECK_NONE_LOADED:
|
||||
if (discarded) {
|
||||
ib_logf(IB_LOG_LEVEL_INFO,
|
||||
"DISCARD flag set for table '%s',"
|
||||
" ignored.",
|
||||
table_name);
|
||||
break;
|
||||
}
|
||||
|
||||
/* It is a normal database startup: create the
|
||||
space object and check that the .ibd file exists.
|
||||
|
|
@ -1127,18 +1148,16 @@ loop:
|
|||
if (filepath) {
|
||||
mem_free(filepath);
|
||||
}
|
||||
} else {
|
||||
ib_logf(IB_LOG_LEVEL_INFO,
|
||||
"DISCARD flag set for table '%s', ignored.",
|
||||
table_name);
|
||||
}
|
||||
|
||||
mem_free(name);
|
||||
break;
|
||||
}
|
||||
|
||||
if (space_id > max_space_id) {
|
||||
max_space_id = space_id;
|
||||
}
|
||||
|
||||
next_tablespace:
|
||||
mem_free(name);
|
||||
mtr_start(&mtr);
|
||||
|
||||
btr_pcur_restore_position(BTR_SEARCH_LEAF, &pcur, &mtr);
|
||||
|
|
@ -1808,6 +1827,23 @@ dict_load_indexes(
|
|||
|
||||
rec = btr_pcur_get_rec(&pcur);
|
||||
|
||||
if ((ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)
|
||||
&& rec_get_n_fields_old(rec)
|
||||
== DICT_NUM_FIELDS__SYS_INDEXES) {
|
||||
const byte* field;
|
||||
ulint len;
|
||||
field = rec_get_nth_field_old(
|
||||
rec, DICT_FLD__SYS_INDEXES__NAME, &len);
|
||||
|
||||
if (len != UNIV_SQL_NULL
|
||||
&& char(*field) == char(TEMP_INDEX_PREFIX)) {
|
||||
/* Skip indexes whose name starts with
|
||||
TEMP_INDEX_PREFIX, because they will
|
||||
be dropped during crash recovery. */
|
||||
goto next_rec;
|
||||
}
|
||||
}
|
||||
|
||||
err_msg = dict_load_index_low(buf, table->name, heap, rec,
|
||||
TRUE, &index);
|
||||
ut_ad((index == NULL && err_msg != NULL)
|
||||
|
|
@ -2317,11 +2353,14 @@ err_exit:
|
|||
table->ibd_file_missing = TRUE;
|
||||
|
||||
} else {
|
||||
if (!(ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)) {
|
||||
ib_logf(IB_LOG_LEVEL_ERROR,
|
||||
"Failed to find tablespace for table '%s' "
|
||||
"in the cache. Attempting to load the "
|
||||
"tablespace with space id %lu.",
|
||||
"Failed to find tablespace for "
|
||||
"table '%s' in the cache. "
|
||||
"Attempting to load the tablespace "
|
||||
"with space id %lu.",
|
||||
table_name, (ulong) table->space);
|
||||
}
|
||||
|
||||
/* Use the remote filepath if needed. */
|
||||
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
|
||||
|
|
@ -2368,13 +2407,15 @@ err_exit:
|
|||
|
||||
/* If there is no tablespace for the table then we only need to
|
||||
load the index definitions. So that we can IMPORT the tablespace
|
||||
later. */
|
||||
if (table->ibd_file_missing) {
|
||||
err = dict_load_indexes(
|
||||
table, heap, DICT_ERR_IGNORE_ALL);
|
||||
} else {
|
||||
err = dict_load_indexes(table, heap, ignore_err);
|
||||
}
|
||||
later. When recovering table locks for resurrected incomplete
|
||||
transactions, the tablespace should exist, because DDL operations
|
||||
were not allowed while the table is being locked by a transaction. */
|
||||
dict_err_ignore_t index_load_err =
|
||||
!(ignore_err & DICT_ERR_IGNORE_RECOVER_LOCK)
|
||||
&& table->ibd_file_missing
|
||||
? DICT_ERR_IGNORE_ALL
|
||||
: ignore_err;
|
||||
err = dict_load_indexes(table, heap, index_load_err);
|
||||
|
||||
if (err == DB_INDEX_CORRUPT) {
|
||||
/* Refuse to load the table if the table has a corrupted
|
||||
|
|
@ -2411,9 +2452,16 @@ err_exit:
|
|||
if (!cached || table->ibd_file_missing) {
|
||||
/* Don't attempt to load the indexes from disk. */
|
||||
} else if (err == DB_SUCCESS) {
|
||||
err = dict_load_foreigns(table->name, TRUE, TRUE);
|
||||
err = dict_load_foreigns(table->name, NULL, true, true,
|
||||
ignore_err);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Load table '%s' failed, the table has missing "
|
||||
"foreign key indexes. Turn off "
|
||||
"'foreign_key_checks' and try again.",
|
||||
table->name);
|
||||
|
||||
dict_table_remove_from_cache(table);
|
||||
table = NULL;
|
||||
} else {
|
||||
|
|
@ -2474,7 +2522,9 @@ UNIV_INTERN
|
|||
dict_table_t*
|
||||
dict_load_table_on_id(
|
||||
/*==================*/
|
||||
table_id_t table_id) /*!< in: table id */
|
||||
table_id_t table_id, /*!< in: table id */
|
||||
dict_err_ignore_t ignore_err) /*!< in: errors to ignore
|
||||
when loading the table */
|
||||
{
|
||||
byte id_buf[8];
|
||||
btr_pcur_t pcur;
|
||||
|
|
@ -2551,7 +2601,7 @@ check_rec:
|
|||
table = dict_load_table(
|
||||
mem_heap_strdupl(
|
||||
heap, (char*) field, len),
|
||||
TRUE, DICT_ERR_IGNORE_NONE);
|
||||
TRUE, ignore_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -2710,18 +2760,25 @@ dict_load_foreign_cols(
|
|||
/***********************************************************************//**
|
||||
Loads a foreign key constraint to the dictionary cache.
|
||||
@return DB_SUCCESS or error code */
|
||||
static __attribute__((nonnull, warn_unused_result))
|
||||
static __attribute__((nonnull(1), warn_unused_result))
|
||||
dberr_t
|
||||
dict_load_foreign(
|
||||
/*==============*/
|
||||
const char* id, /*!< in: foreign constraint id, must be
|
||||
const char* id,
|
||||
/*!< in: foreign constraint id, must be
|
||||
'\0'-terminated */
|
||||
ibool check_charsets,
|
||||
/*!< in: TRUE=check charset compatibility */
|
||||
ibool check_recursive)
|
||||
/*!< in: Whether to record the foreign table
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL
|
||||
to use foreign->foreign_table->col_names */
|
||||
bool check_recursive,
|
||||
/*!< in: whether to record the foreign table
|
||||
parent count to avoid unlimited recursive
|
||||
load of chained foreign tables */
|
||||
bool check_charsets,
|
||||
/*!< in: whether to check charset
|
||||
compatibility */
|
||||
dict_err_ignore_t ignore_err)
|
||||
/*!< in: error to be ignored */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
dict_table_t* sys_foreign;
|
||||
|
|
@ -2890,7 +2947,8 @@ dict_load_foreign(
|
|||
a new foreign key constraint but loading one from the data
|
||||
dictionary. */
|
||||
|
||||
return(dict_foreign_add_to_cache(foreign, check_charsets));
|
||||
return(dict_foreign_add_to_cache(foreign, col_names, check_charsets,
|
||||
ignore_err));
|
||||
}
|
||||
|
||||
/***********************************************************************//**
|
||||
|
|
@ -2903,12 +2961,16 @@ already in the dictionary cache.
|
|||
UNIV_INTERN
|
||||
dberr_t
|
||||
dict_load_foreigns(
|
||||
/*===============*/
|
||||
const char* table_name, /*!< in: table name */
|
||||
ibool check_recursive,/*!< in: Whether to check recursive
|
||||
load of tables chained by FK */
|
||||
ibool check_charsets) /*!< in: TRUE=check charset
|
||||
compatibility */
|
||||
const char** col_names, /*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
bool check_recursive,/*!< in: Whether to check
|
||||
recursive load of tables
|
||||
chained by FK */
|
||||
bool check_charsets, /*!< in: whether to check
|
||||
charset compatibility */
|
||||
dict_err_ignore_t ignore_err) /*!< in: error to be ignored */
|
||||
/*===============*/
|
||||
{
|
||||
ulint tuple_buf[(DTUPLE_EST_ALLOC(1) + sizeof(ulint) - 1)
|
||||
/ sizeof(ulint)];
|
||||
|
|
@ -2992,13 +3054,12 @@ loop:
|
|||
may not be the same case, but the previous comparison showed that they
|
||||
match with no-case. */
|
||||
|
||||
if ((innobase_get_lower_case_table_names() != 2)
|
||||
&& (0 != ut_memcmp(field, table_name, len))) {
|
||||
if (rec_get_deleted_flag(rec, 0)) {
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
if (rec_get_deleted_flag(rec, 0)) {
|
||||
|
||||
if ((innobase_get_lower_case_table_names() != 2)
|
||||
&& (0 != ut_memcmp(field, table_name, len))) {
|
||||
goto next_rec;
|
||||
}
|
||||
|
||||
|
|
@ -3020,7 +3081,8 @@ loop:
|
|||
|
||||
/* Load the foreign constraint definition to the dictionary cache */
|
||||
|
||||
err = dict_load_foreign(fk_id, check_charsets, check_recursive);
|
||||
err = dict_load_foreign(fk_id, col_names,
|
||||
check_recursive, check_charsets, ignore_err);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
btr_pcur_close(&pcur);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
@ -53,10 +53,6 @@ Created 1/8/1996 Heikki Tuuri
|
|||
UNIV_INTERN mysql_pfs_key_t autoinc_mutex_key;
|
||||
#endif /* UNIV_PFS_MUTEX */
|
||||
|
||||
/** Prefix for tmp tables, adopted from sql/table.h */
|
||||
#define tmp_file_prefix "#sql"
|
||||
#define tmp_file_prefix_length 4
|
||||
|
||||
/**********************************************************************//**
|
||||
Creates a table memory object.
|
||||
@return own: table object */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2009, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2009, 2013, 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
|
||||
|
|
@ -34,7 +34,6 @@ Created Jan 06, 2010 Vasil Dimov
|
|||
#include "dict0stats.h"
|
||||
#include "data0type.h" /* dtype_t */
|
||||
#include "db0err.h" /* dberr_t */
|
||||
#include "dyn0dyn.h" /* dyn_array* */
|
||||
#include "page0page.h" /* page_align() */
|
||||
#include "pars0pars.h" /* pars_info_create() */
|
||||
#include "pars0types.h" /* pars_info_t */
|
||||
|
|
@ -47,6 +46,8 @@ Created Jan 06, 2010 Vasil Dimov
|
|||
#include "ut0rnd.h" /* ut_rnd_interval() */
|
||||
#include "ut0ut.h" /* ut_format_name(), ut_time() */
|
||||
|
||||
#include <vector>
|
||||
|
||||
/* Sampling algorithm description @{
|
||||
|
||||
The algorithm is controlled by one number - N_SAMPLE_PAGES(index),
|
||||
|
|
@ -135,12 +136,18 @@ descending to lower levels and fetch N_SAMPLE_PAGES(index) records
|
|||
from that level */
|
||||
#define N_DIFF_REQUIRED(index) (N_SAMPLE_PAGES(index) * 10)
|
||||
|
||||
/* A dynamic array where we store the boundaries of each distinct group
|
||||
of keys. For example if a btree level is:
|
||||
index: 0,1,2,3,4,5,6,7,8,9,10,11,12
|
||||
data: b,b,b,b,b,b,g,g,j,j,j, x, y
|
||||
then we would store 5,7,10,11,12 in the array. */
|
||||
typedef std::vector<ib_uint64_t> boundaries_t;
|
||||
|
||||
/*********************************************************************//**
|
||||
Checks whether an index should be ignored in stats manipulations:
|
||||
* stats fetch
|
||||
* stats recalc
|
||||
* stats save
|
||||
dict_stats_should_ignore_index() @{
|
||||
@return true if exists and all tables are ok */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
|
|
@ -153,12 +160,10 @@ dict_stats_should_ignore_index(
|
|||
|| index->to_be_dropped
|
||||
|| *index->name == TEMP_INDEX_PREFIX);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Checks whether the persistent statistics storage exists and that all
|
||||
tables have the proper structure.
|
||||
dict_stats_persistent_storage_check() @{
|
||||
@return true if exists and all tables are ok */
|
||||
static
|
||||
bool
|
||||
|
|
@ -260,7 +265,6 @@ dict_stats_persistent_storage_check(
|
|||
|
||||
return(true);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Executes a given SQL statement using the InnoDB internal SQL parser
|
||||
|
|
@ -463,8 +467,7 @@ dict_stats_table_clone_create(
|
|||
|
||||
/*********************************************************************//**
|
||||
Free the resources occupied by an object returned by
|
||||
dict_stats_table_clone_create().
|
||||
dict_stats_table_clone_free() @{ */
|
||||
dict_stats_table_clone_create(). */
|
||||
static
|
||||
void
|
||||
dict_stats_table_clone_free(
|
||||
|
|
@ -473,14 +476,12 @@ dict_stats_table_clone_free(
|
|||
{
|
||||
mem_heap_free(t->heap);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Write all zeros (or 1 where it makes sense) into an index
|
||||
statistics members. The resulting stats correspond to an empty index.
|
||||
The caller must own index's table stats latch in X mode
|
||||
(dict_table_stats_lock(table, RW_X_LATCH))
|
||||
dict_stats_empty_index() @{ */
|
||||
(dict_table_stats_lock(table, RW_X_LATCH)) */
|
||||
static
|
||||
void
|
||||
dict_stats_empty_index(
|
||||
|
|
@ -501,12 +502,10 @@ dict_stats_empty_index(
|
|||
index->stat_index_size = 1;
|
||||
index->stat_n_leaf_pages = 1;
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Write all zeros (or 1 where it makes sense) into a table and its indexes'
|
||||
statistics members. The resulting stats correspond to an empty table.
|
||||
dict_stats_empty_table() @{ */
|
||||
statistics members. The resulting stats correspond to an empty table. */
|
||||
static
|
||||
void
|
||||
dict_stats_empty_table(
|
||||
|
|
@ -543,7 +542,6 @@ dict_stats_empty_table(
|
|||
|
||||
dict_table_stats_unlock(table, RW_X_LATCH);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Check whether index's stats are initialized (assert if they are not). */
|
||||
|
|
@ -573,6 +571,7 @@ dict_stats_assert_initialized_index(
|
|||
&index->stat_n_leaf_pages,
|
||||
sizeof(index->stat_n_leaf_pages));
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Check whether table's stats are initialized (assert if they are not). */
|
||||
static
|
||||
|
|
@ -760,8 +759,7 @@ dict_stats_snapshot_create(
|
|||
|
||||
/*********************************************************************//**
|
||||
Free the resources occupied by an object returned by
|
||||
dict_stats_snapshot_create().
|
||||
dict_stats_snapshot_free() @{ */
|
||||
dict_stats_snapshot_create(). */
|
||||
static
|
||||
void
|
||||
dict_stats_snapshot_free(
|
||||
|
|
@ -770,14 +768,12 @@ dict_stats_snapshot_free(
|
|||
{
|
||||
dict_stats_table_clone_free(t);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates new estimates for index statistics. This function is
|
||||
relatively quick and is used to calculate transient statistics that
|
||||
are not saved on disk. This was the only way to calculate statistics
|
||||
before the Persistent Statistics feature was introduced.
|
||||
dict_stats_update_transient_for_index() @{ */
|
||||
before the Persistent Statistics feature was introduced. */
|
||||
static
|
||||
void
|
||||
dict_stats_update_transient_for_index(
|
||||
|
|
@ -826,15 +822,13 @@ dict_stats_update_transient_for_index(
|
|||
dict_stats_empty_index(index);
|
||||
}
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates new estimates for table and index statistics. This function
|
||||
is relatively quick and is used to calculate transient statistics that
|
||||
are not saved on disk.
|
||||
This was the only way to calculate statistics before the
|
||||
Persistent Statistics feature was introduced.
|
||||
dict_stats_update_transient() @{ */
|
||||
Persistent Statistics feature was introduced. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_update_transient(
|
||||
|
|
@ -900,7 +894,6 @@ dict_stats_update_transient(
|
|||
|
||||
table->stat_initialized = TRUE;
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/* @{ Pseudo code about the relation between the following functions
|
||||
|
||||
|
|
@ -938,7 +931,7 @@ dict_stats_analyze_index_level(
|
|||
distinct keys for all prefixes */
|
||||
ib_uint64_t* total_recs, /*!< out: total number of records */
|
||||
ib_uint64_t* total_pages, /*!< out: total number of pages */
|
||||
dyn_array_t* n_diff_boundaries,/*!< out: boundaries of the groups
|
||||
boundaries_t* n_diff_boundaries,/*!< out: boundaries of the groups
|
||||
of distinct keys */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
{
|
||||
|
|
@ -983,9 +976,9 @@ dict_stats_analyze_index_level(
|
|||
/* reset the dynamic arrays n_diff_boundaries[0..n_uniq-1] */
|
||||
if (n_diff_boundaries != NULL) {
|
||||
for (i = 0; i < n_uniq; i++) {
|
||||
dyn_array_free(&n_diff_boundaries[i]);
|
||||
|
||||
dyn_array_create(&n_diff_boundaries[i]);
|
||||
n_diff_boundaries[i].erase(
|
||||
n_diff_boundaries[i].begin(),
|
||||
n_diff_boundaries[i].end());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1113,7 +1106,6 @@ dict_stats_analyze_index_level(
|
|||
record, that is - the last one from
|
||||
a group of equal keys */
|
||||
|
||||
void* p;
|
||||
ib_uint64_t idx;
|
||||
|
||||
/* the index of the current record
|
||||
|
|
@ -1126,11 +1118,7 @@ dict_stats_analyze_index_level(
|
|||
total_recs >= 2 */
|
||||
idx = *total_recs - 2;
|
||||
|
||||
p = dyn_array_push(
|
||||
&n_diff_boundaries[i],
|
||||
sizeof(ib_uint64_t));
|
||||
|
||||
memcpy(p, &idx, sizeof(ib_uint64_t));
|
||||
n_diff_boundaries[i].push_back(idx);
|
||||
}
|
||||
|
||||
/* increment the number of different keys
|
||||
|
|
@ -1191,15 +1179,11 @@ dict_stats_analyze_index_level(
|
|||
last one from the last group of equal keys; this holds for
|
||||
all possible prefixes */
|
||||
for (i = 0; i < n_uniq; i++) {
|
||||
void* p;
|
||||
ib_uint64_t idx;
|
||||
|
||||
idx = *total_recs - 1;
|
||||
|
||||
p = dyn_array_push(&n_diff_boundaries[i],
|
||||
sizeof(ib_uint64_t));
|
||||
|
||||
memcpy(p, &idx, sizeof(ib_uint64_t));
|
||||
n_diff_boundaries[i].push_back(idx);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1226,9 +1210,7 @@ dict_stats_analyze_index_level(
|
|||
for (j = 0; j < n_diff[i]; j++) {
|
||||
ib_uint64_t idx;
|
||||
|
||||
idx = *(ib_uint64_t*) dyn_array_get_element(
|
||||
&n_diff_boundaries[i],
|
||||
j * sizeof(ib_uint64_t));
|
||||
idx = n_diff_boundaries[i][j];
|
||||
|
||||
DEBUG_PRINTF(UINT64PF "=" UINT64PF ", ",
|
||||
j, idx);
|
||||
|
|
@ -1273,8 +1255,7 @@ to the right, which means that in the case of QUIT_ON_FIRST_NON_BORING the
|
|||
returned n_diff can either be 0 (empty page), 1 (the whole page has all keys
|
||||
equal) or 2 (the function found a non-boring record and returned).
|
||||
@return offsets1 or offsets2 (the offsets of *out_rec),
|
||||
or NULL if the page is empty and does not contain user records.
|
||||
dict_stats_scan_page() @{ */
|
||||
or NULL if the page is empty and does not contain user records. */
|
||||
UNIV_INLINE __attribute__((nonnull))
|
||||
ulint*
|
||||
dict_stats_scan_page(
|
||||
|
|
@ -1382,13 +1363,11 @@ func_exit:
|
|||
*out_rec = rec;
|
||||
return(offsets_rec);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Dive below the current position of a cursor and calculate the number of
|
||||
distinct records on the leaf page, when looking at the fist n_prefix
|
||||
columns.
|
||||
dict_stats_analyze_index_below_cur() @{
|
||||
@return number of distinct records on the leaf page */
|
||||
static
|
||||
ib_uint64_t
|
||||
|
|
@ -1511,7 +1490,6 @@ dict_stats_analyze_index_below_cur(
|
|||
|
||||
return(n_diff);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
For a given level in an index select N_SAMPLE_PAGES(index)
|
||||
|
|
@ -1536,7 +1514,7 @@ dict_stats_analyze_index_for_n_prefix(
|
|||
records on the given level,
|
||||
when looking at the first
|
||||
n_prefix columns */
|
||||
dyn_array_t* boundaries, /*!< in: array that contains
|
||||
boundaries_t* boundaries, /*!< in: array that contains
|
||||
n_diff_for_this_prefix
|
||||
integers each of which
|
||||
represents the index (on the
|
||||
|
|
@ -1602,8 +1580,7 @@ dict_stats_analyze_index_for_n_prefix(
|
|||
== !(REC_INFO_MIN_REC_FLAG & rec_get_info_bits(
|
||||
btr_pcur_get_rec(&pcur), page_is_comp(page))));
|
||||
|
||||
last_idx_on_level = *(ib_uint64_t*) dyn_array_get_element(boundaries,
|
||||
(ulint) ((n_diff_for_this_prefix - 1) * sizeof(ib_uint64_t)));
|
||||
last_idx_on_level = boundaries->at(n_diff_for_this_prefix - 1);
|
||||
|
||||
rec_idx = 0;
|
||||
|
||||
|
|
@ -1619,7 +1596,7 @@ dict_stats_analyze_index_for_n_prefix(
|
|||
ib_uint64_t dive_below_idx;
|
||||
|
||||
/* there are n_diff_for_this_prefix elements
|
||||
in the array boundaries[] and we divide those elements
|
||||
in 'boundaries' and we divide those elements
|
||||
into n_recs_to_dive_below segments, for example:
|
||||
|
||||
let n_diff_for_this_prefix=100, n_recs_to_dive_below=4, then:
|
||||
|
|
@ -1658,9 +1635,7 @@ dict_stats_analyze_index_for_n_prefix(
|
|||
ib_uint64_t could be bigger than ulint */
|
||||
rnd = ut_rnd_interval(0, (ulint) (right - left));
|
||||
|
||||
dive_below_idx = *(ib_uint64_t*) dyn_array_get_element(
|
||||
boundaries, (ulint) ((left + rnd)
|
||||
* sizeof(ib_uint64_t)));
|
||||
dive_below_idx = boundaries->at(left + rnd);
|
||||
|
||||
#if 0
|
||||
DEBUG_PRINTF(" %s(): dive below record with index="
|
||||
|
|
@ -1769,9 +1744,13 @@ dict_stats_analyze_index(
|
|||
ib_uint64_t* n_diff_on_level;
|
||||
ib_uint64_t total_recs;
|
||||
ib_uint64_t total_pages;
|
||||
dyn_array_t* n_diff_boundaries;
|
||||
boundaries_t* n_diff_boundaries;
|
||||
mtr_t mtr;
|
||||
ulint size;
|
||||
DBUG_ENTER("dict_stats_analyze_index");
|
||||
|
||||
DBUG_PRINT("info", ("index: %s, online status: %d", index->name,
|
||||
dict_index_get_online_status(index)));
|
||||
|
||||
DEBUG_PRINTF(" %s(index=%s)\n", __func__, index->name);
|
||||
|
||||
|
|
@ -1794,7 +1773,7 @@ dict_stats_analyze_index(
|
|||
switch (size) {
|
||||
case ULINT_UNDEFINED:
|
||||
dict_stats_assert_initialized_index(index);
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
case 0:
|
||||
/* The root node of the tree is a leaf */
|
||||
size = 1;
|
||||
|
|
@ -1848,20 +1827,14 @@ dict_stats_analyze_index(
|
|||
mtr_commit(&mtr);
|
||||
|
||||
dict_stats_assert_initialized_index(index);
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* set to zero */
|
||||
n_diff_on_level = reinterpret_cast<ib_uint64_t*>
|
||||
(mem_zalloc(n_uniq * sizeof(ib_uint64_t)));
|
||||
|
||||
n_diff_boundaries = reinterpret_cast<dyn_array_t*>
|
||||
(mem_alloc(n_uniq * sizeof(dyn_array_t)));
|
||||
|
||||
for (ulint i = 0; i < n_uniq; i++) {
|
||||
/* initialize the dynamic arrays */
|
||||
dyn_array_create(&n_diff_boundaries[i]);
|
||||
}
|
||||
n_diff_boundaries = new boundaries_t[n_uniq];
|
||||
|
||||
/* total_recs is also used to estimate the number of pages on one
|
||||
level below, so at the start we have 1 page (the root) */
|
||||
|
|
@ -2011,15 +1984,12 @@ found_level:
|
|||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
for (ulint i = 0; i < n_uniq; i++) {
|
||||
dyn_array_free(&n_diff_boundaries[i]);
|
||||
}
|
||||
|
||||
mem_free(n_diff_boundaries);
|
||||
delete[] n_diff_boundaries;
|
||||
|
||||
mem_free(n_diff_on_level);
|
||||
|
||||
dict_stats_assert_initialized_index(index);
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
|
@ -2109,7 +2079,6 @@ dict_stats_update_persistent(
|
|||
/*********************************************************************//**
|
||||
Save an individual index's statistic into the persistent statistics
|
||||
storage.
|
||||
dict_stats_save_index_stat() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
static
|
||||
dberr_t
|
||||
|
|
@ -2232,11 +2201,9 @@ dict_stats_save_index_stat(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Save the table's statistics into the persistent statistics storage.
|
||||
dict_stats_save() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
static
|
||||
dberr_t
|
||||
|
|
@ -2401,14 +2368,12 @@ end:
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Called for the row that is selected by
|
||||
SELECT ... FROM mysql.innodb_table_stats WHERE table='...'
|
||||
The second argument is a pointer to the table and the fetched stats are
|
||||
written to it.
|
||||
dict_stats_fetch_table_stats_step() @{
|
||||
@return non-NULL dummy */
|
||||
static
|
||||
ibool
|
||||
|
|
@ -2485,7 +2450,6 @@ dict_stats_fetch_table_stats_step(
|
|||
/* XXX this is not used but returning non-NULL is necessary */
|
||||
return(TRUE);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/** Aux struct used to pass a table and a boolean to
|
||||
dict_stats_fetch_index_stats_step(). */
|
||||
|
|
@ -2511,7 +2475,6 @@ This can be improved if we sort table->indexes in a temporary area just once
|
|||
and then search in that sorted list. Then the complexity will be O(N*log(N)).
|
||||
We assume a table will not have more than 100 indexes, so we go with the
|
||||
simpler N^2 algorithm.
|
||||
dict_stats_fetch_index_stats_step() @{
|
||||
@return non-NULL dummy */
|
||||
static
|
||||
ibool
|
||||
|
|
@ -2752,11 +2715,9 @@ dict_stats_fetch_index_stats_step(
|
|||
/* XXX this is not used but returning non-NULL is necessary */
|
||||
return(TRUE);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Read table's statistics from the persistent statistics storage.
|
||||
dict_stats_fetch_from_ps() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
static
|
||||
dberr_t
|
||||
|
|
@ -2877,17 +2838,17 @@ dict_stats_fetch_from_ps(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Fetches or calculates new estimates for index statistics.
|
||||
dict_stats_update_for_index() @{ */
|
||||
Fetches or calculates new estimates for index statistics. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_update_for_index(
|
||||
/*========================*/
|
||||
dict_index_t* index) /*!< in/out: index */
|
||||
{
|
||||
DBUG_ENTER("dict_stats_update_for_index");
|
||||
|
||||
ut_ad(!mutex_own(&dict_sys->mutex));
|
||||
|
||||
if (dict_stats_is_persistent_enabled(index->table)) {
|
||||
|
|
@ -2897,7 +2858,7 @@ dict_stats_update_for_index(
|
|||
dict_stats_analyze_index(index);
|
||||
dict_table_stats_unlock(index->table, RW_X_LATCH);
|
||||
dict_stats_save(index->table);
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
/* else */
|
||||
|
||||
|
|
@ -2920,8 +2881,9 @@ dict_stats_update_for_index(
|
|||
dict_table_stats_lock(index->table, RW_X_LATCH);
|
||||
dict_stats_update_transient_for_index(index);
|
||||
dict_table_stats_unlock(index->table, RW_X_LATCH);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Calculates new estimates for table and index statistics. The statistics
|
||||
|
|
@ -2962,7 +2924,9 @@ dict_stats_update(
|
|||
switch (stats_upd_option) {
|
||||
case DICT_STATS_RECALC_PERSISTENT:
|
||||
|
||||
ut_ad(!srv_read_only_mode);
|
||||
if (srv_read_only_mode) {
|
||||
goto transient;
|
||||
}
|
||||
|
||||
/* Persistent recalculation requested, called from
|
||||
1) ANALYZE TABLE, or
|
||||
|
|
@ -3063,8 +3027,6 @@ dict_stats_update(
|
|||
|
||||
dict_table_t* t;
|
||||
|
||||
ut_ad(!srv_read_only_mode);
|
||||
|
||||
/* Create a dummy table object with the same name and
|
||||
indexes, suitable for fetching the stats into it. */
|
||||
t = dict_stats_table_clone_create(table);
|
||||
|
|
@ -3098,6 +3060,10 @@ dict_stats_update(
|
|||
|
||||
dict_stats_table_clone_free(t);
|
||||
|
||||
if (srv_read_only_mode) {
|
||||
goto transient;
|
||||
}
|
||||
|
||||
if (dict_stats_auto_recalc_is_enabled(table)) {
|
||||
return(dict_stats_update(
|
||||
table,
|
||||
|
|
@ -3162,7 +3128,6 @@ rolling back dict transactions.
|
|||
marko: If ibuf merges are not disabled, we need to scan the *.ibd files.
|
||||
But we shouldn't open *.ibd files before we have rolled back dict
|
||||
transactions and opened the SYS_* records for the *.ibd files.
|
||||
dict_stats_drop_index() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
|
|
@ -3244,14 +3209,12 @@ dict_stats_drop_index(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Executes
|
||||
DELETE FROM mysql.innodb_table_stats
|
||||
WHERE database_name = '...' AND table_name = '...';
|
||||
Creates its own transaction and commits it.
|
||||
dict_stats_delete_from_table_stats() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
UNIV_INLINE
|
||||
dberr_t
|
||||
|
|
@ -3265,7 +3228,7 @@ dict_stats_delete_from_table_stats(
|
|||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
#endif /* UNIV_STAT */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
pinfo = pars_info_create();
|
||||
|
|
@ -3284,14 +3247,12 @@ dict_stats_delete_from_table_stats(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Executes
|
||||
DELETE FROM mysql.innodb_index_stats
|
||||
WHERE database_name = '...' AND table_name = '...';
|
||||
Creates its own transaction and commits it.
|
||||
dict_stats_delete_from_index_stats() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
UNIV_INLINE
|
||||
dberr_t
|
||||
|
|
@ -3305,7 +3266,7 @@ dict_stats_delete_from_index_stats(
|
|||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
#endif /* UNIV_STAT */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
pinfo = pars_info_create();
|
||||
|
|
@ -3324,13 +3285,11 @@ dict_stats_delete_from_index_stats(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Removes the statistics for a table and all of its indexes from the
|
||||
persistent statistics storage if it exists and if there is data stored for
|
||||
the table. This function creates its own transaction and commits it.
|
||||
dict_stats_drop_table() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
|
|
@ -3347,7 +3306,7 @@ dict_stats_drop_table(
|
|||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
#endif /* UNIV_STAT */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
/* skip tables that do not contain a database name
|
||||
|
|
@ -3403,7 +3362,6 @@ dict_stats_drop_table(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Executes
|
||||
|
|
@ -3411,7 +3369,6 @@ UPDATE mysql.innodb_table_stats SET
|
|||
database_name = '...', table_name = '...'
|
||||
WHERE database_name = '...' AND table_name = '...';
|
||||
Creates its own transaction and commits it.
|
||||
dict_stats_rename_in_table_stats() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
UNIV_INLINE
|
||||
dberr_t
|
||||
|
|
@ -3427,7 +3384,7 @@ dict_stats_rename_in_table_stats(
|
|||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
#endif /* UNIV_STAT */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
pinfo = pars_info_create();
|
||||
|
|
@ -3451,7 +3408,6 @@ dict_stats_rename_in_table_stats(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Executes
|
||||
|
|
@ -3459,7 +3415,6 @@ UPDATE mysql.innodb_index_stats SET
|
|||
database_name = '...', table_name = '...'
|
||||
WHERE database_name = '...' AND table_name = '...';
|
||||
Creates its own transaction and commits it.
|
||||
dict_stats_rename_in_index_stats() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
UNIV_INLINE
|
||||
dberr_t
|
||||
|
|
@ -3475,7 +3430,7 @@ dict_stats_rename_in_index_stats(
|
|||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
#endif /* UNIV_STAT */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
pinfo = pars_info_create();
|
||||
|
|
@ -3499,12 +3454,10 @@ dict_stats_rename_in_index_stats(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Renames a table in InnoDB persistent stats storage.
|
||||
This function creates its own transaction and commits it.
|
||||
dict_stats_rename_table() @{
|
||||
@return DB_SUCCESS or error code */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
|
|
@ -3524,7 +3477,7 @@ dict_stats_rename_table(
|
|||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(!rw_lock_own(&dict_operation_lock, RW_LOCK_EX));
|
||||
#endif /* UNIV_STAT */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ut_ad(!mutex_own(&dict_sys->mutex));
|
||||
|
||||
/* skip innodb_table_stats and innodb_index_stats themselves */
|
||||
|
|
@ -3658,7 +3611,6 @@ dict_stats_rename_table(
|
|||
|
||||
return(ret);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/* tests @{ */
|
||||
#ifdef UNIV_COMPILE_TEST_FUNCS
|
||||
|
|
@ -4050,5 +4002,3 @@ test_dict_stats_all()
|
|||
/* @} */
|
||||
|
||||
#endif /* UNIV_HOTBACKUP */
|
||||
|
||||
/* vim: set foldmethod=marker foldmarker=@{,@}: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, 2013, 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
|
||||
|
|
@ -28,6 +28,10 @@ Created Apr 25, 2012 Vasil Dimov
|
|||
#include "dict0stats.h"
|
||||
#include "dict0stats_bg.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
# include "dict0stats_bg.ic"
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
|
||||
/** Minimum time interval between stats recalc for a given table */
|
||||
|
|
@ -95,8 +99,7 @@ Add a table to the recalc pool, which is processed by the
|
|||
background stats gathering thread. Only the table id is added to the
|
||||
list, so the table can be closed after being enqueued and it will be
|
||||
opened when needed. If the table does not exist later (has been DROPped),
|
||||
then it will be removed from the pool and skipped.
|
||||
dict_stats_recalc_pool_add() @{ */
|
||||
then it will be removed from the pool and skipped. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_recalc_pool_add(
|
||||
|
|
@ -124,12 +127,10 @@ dict_stats_recalc_pool_add(
|
|||
|
||||
os_event_set(dict_stats_event);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Get a table from the auto recalc pool. The returned table id is removed
|
||||
from the pool.
|
||||
dict_stats_recalc_pool_get() @{
|
||||
@return true if the pool was non-empty and "id" was set, false otherwise */
|
||||
static
|
||||
bool
|
||||
|
|
@ -155,7 +156,6 @@ dict_stats_recalc_pool_get(
|
|||
|
||||
return(true);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Delete a given table from the auto recalc pool.
|
||||
|
|
@ -188,46 +188,30 @@ dict_stats_recalc_pool_del(
|
|||
}
|
||||
|
||||
/*****************************************************************//**
|
||||
Wait until background stats thread has stopped using the specified table(s).
|
||||
Wait until background stats thread has stopped using the specified table.
|
||||
The caller must have locked the data dictionary using
|
||||
row_mysql_lock_data_dictionary() and this function may unlock it temporarily
|
||||
and restore the lock before it exits.
|
||||
The background stats thead is guaranteed not to start using the specified
|
||||
tables after this function returns and before the caller unlocks the data
|
||||
The background stats thread is guaranteed not to start using the specified
|
||||
table after this function returns and before the caller unlocks the data
|
||||
dictionary because it sets the BG_STAT_IN_PROGRESS bit in table->stats_bg_flag
|
||||
under dict_sys->mutex.
|
||||
dict_stats_wait_bg_to_stop_using_table() @{ */
|
||||
under dict_sys->mutex. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_wait_bg_to_stop_using_tables(
|
||||
/*====================================*/
|
||||
dict_table_t* table1, /*!< in/out: table1 */
|
||||
dict_table_t* table2, /*!< in/out: table2, could be NULL */
|
||||
dict_stats_wait_bg_to_stop_using_table(
|
||||
/*===================================*/
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
trx_t* trx) /*!< in/out: transaction to use for
|
||||
unlocking/locking the data dict */
|
||||
{
|
||||
ut_ad(!srv_read_only_mode);
|
||||
|
||||
while ((table1->stats_bg_flag & BG_STAT_IN_PROGRESS)
|
||||
|| (table2 != NULL
|
||||
&& (table2->stats_bg_flag & BG_STAT_IN_PROGRESS))) {
|
||||
|
||||
table1->stats_bg_flag |= BG_STAT_SHOULD_QUIT;
|
||||
if (table2 != NULL) {
|
||||
table2->stats_bg_flag |= BG_STAT_SHOULD_QUIT;
|
||||
}
|
||||
|
||||
row_mysql_unlock_data_dictionary(trx);
|
||||
os_thread_sleep(250000);
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
while (!dict_stats_stop_bg(table)) {
|
||||
DICT_STATS_BG_YIELD(trx);
|
||||
}
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Initialize global variables needed for the operation of dict_stats_thread()
|
||||
Must be called before dict_stats_thread() is started.
|
||||
dict_stats_thread_init() @{ */
|
||||
Must be called before dict_stats_thread() is started. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_thread_init()
|
||||
|
|
@ -255,12 +239,10 @@ dict_stats_thread_init()
|
|||
|
||||
dict_stats_recalc_pool_init();
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Free resources allocated by dict_stats_thread_init(), must be called
|
||||
after dict_stats_thread() has exited.
|
||||
dict_stats_thread_deinit() @{ */
|
||||
after dict_stats_thread() has exited. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_thread_deinit()
|
||||
|
|
@ -277,12 +259,10 @@ dict_stats_thread_deinit()
|
|||
os_event_free(dict_stats_event);
|
||||
dict_stats_event = NULL;
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Get the first table that has been added for auto recalc and eventually
|
||||
update its stats.
|
||||
dict_stats_process_entry_from_recalc_pool() @{ */
|
||||
update its stats. */
|
||||
static
|
||||
void
|
||||
dict_stats_process_entry_from_recalc_pool()
|
||||
|
|
@ -302,7 +282,7 @@ dict_stats_process_entry_from_recalc_pool()
|
|||
|
||||
mutex_enter(&dict_sys->mutex);
|
||||
|
||||
table = dict_table_open_on_id(table_id, TRUE, FALSE);
|
||||
table = dict_table_open_on_id(table_id, TRUE, DICT_TABLE_OP_NORMAL);
|
||||
|
||||
if (table == NULL) {
|
||||
/* table does not exist, must have been DROPped
|
||||
|
|
@ -351,13 +331,11 @@ dict_stats_process_entry_from_recalc_pool()
|
|||
|
||||
mutex_exit(&dict_sys->mutex);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
This is the thread for background stats gathering. It pops tables, from
|
||||
the auto recalc list and proceeds them, eventually recalculating their
|
||||
statistics.
|
||||
dict_stats_thread() @{
|
||||
@return this function does not return, it calls os_thread_exit() */
|
||||
extern "C" UNIV_INTERN
|
||||
os_thread_ret_t
|
||||
|
|
@ -397,6 +375,3 @@ DECLARE_THREAD(dict_stats_thread)(
|
|||
|
||||
OS_THREAD_DUMMY_RETURN;
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/* vim: set foldmethod=marker foldmarker=@{,@}: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -35,7 +35,7 @@ UNIV_INTERN
|
|||
dyn_block_t*
|
||||
dyn_array_add_block(
|
||||
/*================*/
|
||||
dyn_array_t* arr) /*!< in: dyn array */
|
||||
dyn_array_t* arr) /*!< in/out: dyn array */
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
dyn_block_t* block;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -147,6 +147,8 @@ struct fil_node_t {
|
|||
char* name; /*!< path to the file */
|
||||
ibool open; /*!< TRUE if file open */
|
||||
os_file_t handle; /*!< OS handle to the file, if file open */
|
||||
os_event_t sync_event;/*!< Condition event to group and
|
||||
serialize calls to fsync */
|
||||
ibool is_raw_disk;/*!< TRUE if the 'file' is actually a raw
|
||||
device or a raw disk partition */
|
||||
ulint size; /*!< size of the file in database pages, 0 if
|
||||
|
|
@ -374,9 +376,10 @@ NOTE: you must call fil_mutex_enter_and_prepare_for_io() first!
|
|||
Prepares a file node for i/o. Opens the file if it is closed. Updates the
|
||||
pending i/o's field in the node and the system appropriately. Takes the node
|
||||
off the LRU list if it is in the LRU list. The caller must hold the fil_sys
|
||||
mutex. */
|
||||
mutex.
|
||||
@return false if the file can't be opened, otherwise true */
|
||||
static
|
||||
void
|
||||
bool
|
||||
fil_node_prepare_for_io(
|
||||
/*====================*/
|
||||
fil_node_t* node, /*!< in: file node */
|
||||
|
|
@ -416,7 +419,7 @@ UNIV_INLINE
|
|||
dberr_t
|
||||
fil_read(
|
||||
/*=====*/
|
||||
ibool sync, /*!< in: TRUE if synchronous aio is desired */
|
||||
bool sync, /*!< in: true if synchronous aio is desired */
|
||||
ulint space_id, /*!< in: space id */
|
||||
ulint zip_size, /*!< in: compressed page size in bytes;
|
||||
0 for uncompressed pages */
|
||||
|
|
@ -445,7 +448,7 @@ UNIV_INLINE
|
|||
dberr_t
|
||||
fil_write(
|
||||
/*======*/
|
||||
ibool sync, /*!< in: TRUE if synchronous aio is desired */
|
||||
bool sync, /*!< in: true if synchronous aio is desired */
|
||||
ulint space_id, /*!< in: space id */
|
||||
ulint zip_size, /*!< in: compressed page size in bytes;
|
||||
0 for uncompressed pages */
|
||||
|
|
@ -649,6 +652,7 @@ fil_node_create(
|
|||
|
||||
ut_a(!is_raw || srv_start_raw_disk_in_use);
|
||||
|
||||
node->sync_event = os_event_create();
|
||||
node->is_raw_disk = is_raw;
|
||||
node->size = size;
|
||||
node->magic_n = FIL_NODE_MAGIC_N;
|
||||
|
|
@ -689,9 +693,10 @@ fil_node_create(
|
|||
|
||||
/********************************************************************//**
|
||||
Opens a file of a node of a tablespace. The caller must own the fil_system
|
||||
mutex. */
|
||||
mutex.
|
||||
@return false if the file can't be opened, otherwise true */
|
||||
static
|
||||
void
|
||||
bool
|
||||
fil_node_open_file(
|
||||
/*===============*/
|
||||
fil_node_t* node, /*!< in: file node */
|
||||
|
|
@ -729,12 +734,12 @@ fil_node_open_file(
|
|||
|
||||
ut_print_timestamp(stderr);
|
||||
|
||||
fprintf(stderr,
|
||||
" InnoDB: Fatal error: cannot open %s\n."
|
||||
"InnoDB: Have you deleted .ibd files"
|
||||
" under a running mysqld server?\n",
|
||||
ib_logf(IB_LOG_LEVEL_WARN, "InnoDB: Error: cannot "
|
||||
"open %s\n. InnoDB: Have you deleted .ibd "
|
||||
"files under a running mysqld server?\n",
|
||||
node->name);
|
||||
ut_a(0);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
size_bytes = os_file_get_size(node->handle);
|
||||
|
|
@ -879,6 +884,8 @@ add_size:
|
|||
/* Put the node to the LRU list */
|
||||
UT_LIST_ADD_FIRST(LRU, system->LRU, node);
|
||||
}
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
@ -1150,6 +1157,7 @@ fil_node_free(
|
|||
there are no unflushed modifications in the file */
|
||||
|
||||
node->modification_counter = node->flush_counter;
|
||||
os_event_set(node->sync_event);
|
||||
|
||||
if (fil_buffering_disabled(space)) {
|
||||
|
||||
|
|
@ -1173,6 +1181,7 @@ fil_node_free(
|
|||
|
||||
UT_LIST_REMOVE(chain, space->chain, node);
|
||||
|
||||
os_event_free(node->sync_event);
|
||||
mem_free(node->name);
|
||||
mem_free(node);
|
||||
}
|
||||
|
|
@ -1242,7 +1251,8 @@ fil_space_create(
|
|||
if (space != 0) {
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
"Tablespace '%s' exists in the cache "
|
||||
"with id %lu", name, (ulong) id);
|
||||
"with id %lu != %lu",
|
||||
name, (ulong) space->id, (ulong) id);
|
||||
|
||||
if (id == 0 || purpose != FIL_TABLESPACE) {
|
||||
|
||||
|
|
@ -1481,6 +1491,21 @@ fil_space_get_space(
|
|||
if (space->size == 0 && space->purpose == FIL_TABLESPACE) {
|
||||
ut_a(id != 0);
|
||||
|
||||
mutex_exit(&fil_system->mutex);
|
||||
|
||||
/* It is possible that the space gets evicted at this point
|
||||
before the fil_mutex_enter_and_prepare_for_io() acquires
|
||||
the fil_system->mutex. Check for this after completing the
|
||||
call to fil_mutex_enter_and_prepare_for_io(). */
|
||||
fil_mutex_enter_and_prepare_for_io(id);
|
||||
|
||||
/* We are still holding the fil_system->mutex. Check if
|
||||
the space is still in memory cache. */
|
||||
space = fil_space_get_by_id(id);
|
||||
if (space == NULL) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* The following code must change when InnoDB supports
|
||||
multiple datafiles per tablespace. */
|
||||
ut_a(1 == UT_LIST_GET_LEN(space->chain));
|
||||
|
|
@ -1491,7 +1516,11 @@ fil_space_get_space(
|
|||
the file yet; the following calls will open it and update the
|
||||
size fields */
|
||||
|
||||
fil_node_prepare_for_io(node, fil_system, space);
|
||||
if (!fil_node_prepare_for_io(node, fil_system, space)) {
|
||||
/* The single-table tablespace can't be opened,
|
||||
because the ibd file is missing. */
|
||||
return(NULL);
|
||||
}
|
||||
fil_node_complete_io(node, fil_system, OS_FILE_READ);
|
||||
}
|
||||
|
||||
|
|
@ -1552,8 +1581,7 @@ fil_space_get_size(
|
|||
ulint size;
|
||||
|
||||
ut_ad(fil_system);
|
||||
|
||||
fil_mutex_enter_and_prepare_for_io(id);
|
||||
mutex_enter(&fil_system->mutex);
|
||||
|
||||
space = fil_space_get_space(id);
|
||||
|
||||
|
|
@ -1583,7 +1611,7 @@ fil_space_get_flags(
|
|||
return(0);
|
||||
}
|
||||
|
||||
fil_mutex_enter_and_prepare_for_io(id);
|
||||
mutex_enter(&fil_system->mutex);
|
||||
|
||||
space = fil_space_get_space(id);
|
||||
|
||||
|
|
@ -1700,7 +1728,15 @@ fil_open_log_and_system_tablespace_files(void)
|
|||
node = UT_LIST_GET_NEXT(chain, node)) {
|
||||
|
||||
if (!node->open) {
|
||||
fil_node_open_file(node, fil_system, space);
|
||||
if (!fil_node_open_file(node, fil_system,
|
||||
space)) {
|
||||
/* This func is called during server's
|
||||
startup. If some file of log or system
|
||||
tablespace is missing, the server
|
||||
can't start successfully. So we should
|
||||
assert for it. */
|
||||
ut_a(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (fil_system->max_n_open < 10 + fil_system->n_open) {
|
||||
|
|
@ -1929,11 +1965,64 @@ fil_write_flushed_lsn_to_data_files(
|
|||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Checks the consistency of the first data page of a tablespace
|
||||
at database startup.
|
||||
@retval NULL on success, or if innodb_force_recovery is set
|
||||
@return pointer to an error message string */
|
||||
static __attribute__((warn_unused_result))
|
||||
const char*
|
||||
fil_check_first_page(
|
||||
/*=================*/
|
||||
const page_t* page) /*!< in: data page */
|
||||
{
|
||||
ulint space_id;
|
||||
ulint flags;
|
||||
|
||||
if (srv_force_recovery >= SRV_FORCE_IGNORE_CORRUPT) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
space_id = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_ID + page);
|
||||
flags = mach_read_from_4(FSP_HEADER_OFFSET + FSP_SPACE_FLAGS + page);
|
||||
|
||||
if (UNIV_PAGE_SIZE != fsp_flags_get_page_size(flags)) {
|
||||
return("innodb-page-size mismatch");
|
||||
}
|
||||
|
||||
if (!space_id && !flags) {
|
||||
ulint nonzero_bytes = UNIV_PAGE_SIZE;
|
||||
const byte* b = page;
|
||||
|
||||
while (!*b && --nonzero_bytes) {
|
||||
b++;
|
||||
}
|
||||
|
||||
if (!nonzero_bytes) {
|
||||
return("space header page consists of zero bytes");
|
||||
}
|
||||
}
|
||||
|
||||
if (buf_page_is_corrupted(
|
||||
false, page, fsp_flags_get_zip_size(flags))) {
|
||||
return("checksum mismatch");
|
||||
}
|
||||
|
||||
if (page_get_space_id(page) == space_id
|
||||
&& page_get_page_no(page) == 0) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
return("inconsistent data in space header");
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Reads the flushed lsn, arch no, and tablespace flag fields from a data
|
||||
file at database startup. */
|
||||
file at database startup.
|
||||
@retval NULL on success, or if innodb_force_recovery is set
|
||||
@return pointer to an error message string */
|
||||
UNIV_INTERN
|
||||
void
|
||||
const char*
|
||||
fil_read_first_page(
|
||||
/*================*/
|
||||
os_file_t data_file, /*!< in: open data file */
|
||||
|
|
@ -1956,6 +2045,7 @@ fil_read_first_page(
|
|||
byte* buf;
|
||||
byte* page;
|
||||
lsn_t flushed_lsn;
|
||||
const char* check_msg = NULL;
|
||||
|
||||
buf = static_cast<byte*>(ut_malloc(2 * UNIV_PAGE_SIZE));
|
||||
|
||||
|
|
@ -1971,8 +2061,16 @@ fil_read_first_page(
|
|||
|
||||
flushed_lsn = mach_read_from_8(page + FIL_PAGE_FILE_FLUSH_LSN);
|
||||
|
||||
if (!one_read_already) {
|
||||
check_msg = fil_check_first_page(page);
|
||||
}
|
||||
|
||||
ut_free(buf);
|
||||
|
||||
if (check_msg) {
|
||||
return(check_msg);
|
||||
}
|
||||
|
||||
if (!one_read_already) {
|
||||
*min_flushed_lsn = flushed_lsn;
|
||||
*max_flushed_lsn = flushed_lsn;
|
||||
|
|
@ -1980,7 +2078,7 @@ fil_read_first_page(
|
|||
*min_arch_log_no = arch_log_no;
|
||||
*max_arch_log_no = arch_log_no;
|
||||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
return;
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (*min_flushed_lsn > flushed_lsn) {
|
||||
|
|
@ -1997,6 +2095,8 @@ fil_read_first_page(
|
|||
*max_arch_log_no = arch_log_no;
|
||||
}
|
||||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/*================ SINGLE-TABLE TABLESPACES ==========================*/
|
||||
|
|
@ -2567,7 +2667,7 @@ fil_close_tablespace(
|
|||
|
||||
char* cfg_name = fil_make_cfg_name(path);
|
||||
|
||||
os_file_delete_if_exists(cfg_name);
|
||||
os_file_delete_if_exists(innodb_file_data_key, cfg_name);
|
||||
|
||||
mem_free(path);
|
||||
mem_free(cfg_name);
|
||||
|
|
@ -2650,7 +2750,7 @@ fil_delete_tablespace(
|
|||
when we drop the database the remove directory will fail. */
|
||||
{
|
||||
char* cfg_name = fil_make_cfg_name(path);
|
||||
os_file_delete_if_exists(cfg_name);
|
||||
os_file_delete_if_exists(innodb_file_data_key, cfg_name);
|
||||
mem_free(cfg_name);
|
||||
}
|
||||
|
||||
|
|
@ -2678,7 +2778,8 @@ fil_delete_tablespace(
|
|||
|
||||
if (err != DB_SUCCESS) {
|
||||
rw_lock_x_unlock(&space->latch);
|
||||
} else if (!os_file_delete(path) && !os_file_delete_if_exists(path)) {
|
||||
} else if (!os_file_delete(innodb_file_data_key, path)
|
||||
&& !os_file_delete_if_exists(innodb_file_data_key, path)) {
|
||||
|
||||
/* Note: This is because we have removed the
|
||||
tablespace instance from the cache. */
|
||||
|
|
@ -3147,7 +3248,7 @@ fil_delete_link_file(
|
|||
{
|
||||
char* link_filepath = fil_make_isl_name(tablename);
|
||||
|
||||
os_file_delete_if_exists(link_filepath);
|
||||
os_file_delete_if_exists(innodb_file_data_key, link_filepath);
|
||||
|
||||
mem_free(link_filepath);
|
||||
}
|
||||
|
|
@ -3458,7 +3559,7 @@ error_exit_1:
|
|||
error_exit_2:
|
||||
os_file_close(file);
|
||||
if (err != DB_SUCCESS) {
|
||||
os_file_delete(path);
|
||||
os_file_delete(innodb_file_data_key, path);
|
||||
}
|
||||
error_exit_3:
|
||||
mem_free(path);
|
||||
|
|
@ -3473,12 +3574,25 @@ static
|
|||
void
|
||||
fil_report_bad_tablespace(
|
||||
/*======================*/
|
||||
char* filepath, /*!< in: filepath */
|
||||
const char* filepath, /*!< in: filepath */
|
||||
const char* check_msg, /*!< in: fil_check_first_page() */
|
||||
ulint found_id, /*!< in: found space ID */
|
||||
ulint found_flags, /*!< in: found flags */
|
||||
ulint expected_id, /*!< in: expected space id */
|
||||
ulint expected_flags) /*!< in: expected flags */
|
||||
{
|
||||
if (check_msg) {
|
||||
ib_logf(IB_LOG_LEVEL_ERROR,
|
||||
"Error %s in file '%s',"
|
||||
"tablespace id=%lu, flags=%lu. "
|
||||
"Please refer to "
|
||||
REFMAN "innodb-troubleshooting-datadict.html "
|
||||
"for how to resolve the issue.",
|
||||
check_msg, filepath,
|
||||
(ulong) expected_id, (ulong) expected_flags);
|
||||
return;
|
||||
}
|
||||
|
||||
ib_logf(IB_LOG_LEVEL_ERROR,
|
||||
"In file '%s', tablespace id and flags are %lu and %lu, "
|
||||
"but in the InnoDB data dictionary they are %lu and %lu. "
|
||||
|
|
@ -3493,6 +3607,7 @@ fil_report_bad_tablespace(
|
|||
|
||||
struct fsp_open_info {
|
||||
ibool success; /*!< Has the tablespace been opened? */
|
||||
const char* check_msg; /*!< fil_check_first_page() message */
|
||||
ibool valid; /*!< Is the tablespace valid? */
|
||||
os_file_t file; /*!< File handle */
|
||||
char* filepath; /*!< File path to open */
|
||||
|
|
@ -3635,48 +3750,50 @@ fil_open_single_table_tablespace(
|
|||
|
||||
/* Read the first page of the datadir tablespace, if found. */
|
||||
if (def.success) {
|
||||
fil_read_first_page(
|
||||
def.check_msg = fil_read_first_page(
|
||||
def.file, FALSE, &def.flags, &def.id,
|
||||
#ifdef UNIV_LOG_ARCHIVE
|
||||
&space_arch_log_no, &space_arch_log_no,
|
||||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
&def.lsn, &def.lsn);
|
||||
def.valid = !def.check_msg;
|
||||
|
||||
/* Validate this single-table-tablespace with SYS_TABLES,
|
||||
but do not compare the DATA_DIR flag, in case the
|
||||
tablespace was relocated. */
|
||||
ulint mod_def_flags = def.flags & ~FSP_FLAGS_MASK_DATA_DIR;
|
||||
if (def.id == id && mod_def_flags == mod_flags) {
|
||||
if (def.valid && def.id == id
|
||||
&& (def.flags & ~FSP_FLAGS_MASK_DATA_DIR) == mod_flags) {
|
||||
valid_tablespaces_found++;
|
||||
def.valid = TRUE;
|
||||
} else {
|
||||
def.valid = false;
|
||||
/* Do not use this tablespace. */
|
||||
fil_report_bad_tablespace(
|
||||
def.filepath, def.id,
|
||||
def.filepath, def.check_msg, def.id,
|
||||
def.flags, id, flags);
|
||||
}
|
||||
}
|
||||
|
||||
/* Read the first page of the remote tablespace */
|
||||
if (remote.success) {
|
||||
fil_read_first_page(
|
||||
remote.check_msg = fil_read_first_page(
|
||||
remote.file, FALSE, &remote.flags, &remote.id,
|
||||
#ifdef UNIV_LOG_ARCHIVE
|
||||
&remote.arch_log_no, &remote.arch_log_no,
|
||||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
&remote.lsn, &remote.lsn);
|
||||
remote.valid = !remote.check_msg;
|
||||
|
||||
/* Validate this single-table-tablespace with SYS_TABLES,
|
||||
but do not compare the DATA_DIR flag, in case the
|
||||
tablespace was relocated. */
|
||||
ulint mod_remote_flags = remote.flags & ~FSP_FLAGS_MASK_DATA_DIR;
|
||||
if (remote.id == id && mod_remote_flags == mod_flags) {
|
||||
if (remote.valid && remote.id == id
|
||||
&& (remote.flags & ~FSP_FLAGS_MASK_DATA_DIR) == mod_flags) {
|
||||
valid_tablespaces_found++;
|
||||
remote.valid = TRUE;
|
||||
} else {
|
||||
remote.valid = false;
|
||||
/* Do not use this linked tablespace. */
|
||||
fil_report_bad_tablespace(
|
||||
remote.filepath, remote.id,
|
||||
remote.filepath, remote.check_msg, remote.id,
|
||||
remote.flags, id, flags);
|
||||
link_file_is_bad = true;
|
||||
}
|
||||
|
|
@ -3684,24 +3801,25 @@ fil_open_single_table_tablespace(
|
|||
|
||||
/* Read the first page of the datadir tablespace, if found. */
|
||||
if (dict.success) {
|
||||
fil_read_first_page(
|
||||
dict.check_msg = fil_read_first_page(
|
||||
dict.file, FALSE, &dict.flags, &dict.id,
|
||||
#ifdef UNIV_LOG_ARCHIVE
|
||||
&dict.arch_log_no, &dict.arch_log_no,
|
||||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
&dict.lsn, &dict.lsn);
|
||||
dict.valid = !dict.check_msg;
|
||||
|
||||
/* Validate this single-table-tablespace with SYS_TABLES,
|
||||
but do not compare the DATA_DIR flag, in case the
|
||||
tablespace was relocated. */
|
||||
ulint mod_dict_flags = dict.flags & ~FSP_FLAGS_MASK_DATA_DIR;
|
||||
if (dict.id == id && mod_dict_flags == mod_flags) {
|
||||
if (dict.valid && dict.id == id
|
||||
&& (dict.flags & ~FSP_FLAGS_MASK_DATA_DIR) == mod_flags) {
|
||||
valid_tablespaces_found++;
|
||||
dict.valid = TRUE;
|
||||
} else {
|
||||
dict.valid = false;
|
||||
/* Do not use this tablespace. */
|
||||
fil_report_bad_tablespace(
|
||||
dict.filepath, dict.id,
|
||||
dict.filepath, dict.check_msg, dict.id,
|
||||
dict.flags, id, flags);
|
||||
}
|
||||
}
|
||||
|
|
@ -3914,16 +4032,22 @@ fil_validate_single_table_tablespace(
|
|||
const char* tablename, /*!< in: database/tablename */
|
||||
fsp_open_info* fsp) /*!< in/out: tablespace info */
|
||||
{
|
||||
fil_read_first_page(
|
||||
if (const char* check_msg = fil_read_first_page(
|
||||
fsp->file, FALSE, &fsp->flags, &fsp->id,
|
||||
#ifdef UNIV_LOG_ARCHIVE
|
||||
&fsp->arch_log_no, &fsp->arch_log_no,
|
||||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
&fsp->lsn, &fsp->lsn);
|
||||
&fsp->lsn, &fsp->lsn)) {
|
||||
ib_logf(IB_LOG_LEVEL_ERROR,
|
||||
"%s in tablespace %s (table %s)",
|
||||
check_msg, fsp->filepath, tablename);
|
||||
fsp->success = FALSE;
|
||||
return;
|
||||
}
|
||||
|
||||
if (fsp->id == ULINT_UNDEFINED || fsp->id == 0) {
|
||||
fprintf(stderr,
|
||||
" InnoDB: Error: Tablespace is not sensible;"
|
||||
ib_logf(IB_LOG_LEVEL_ERROR,
|
||||
"Tablespace is not sensible;"
|
||||
" Table: %s Space ID: %lu Filepath: %s\n",
|
||||
tablename, (ulong) fsp->id, fsp->filepath);
|
||||
fsp->success = FALSE;
|
||||
|
|
@ -4051,6 +4175,19 @@ fil_load_single_table_tablespace(
|
|||
fprintf(stderr,
|
||||
"InnoDB: Error: could not open single-table"
|
||||
" tablespace file %s\n", def.filepath);
|
||||
|
||||
if (!strncmp(filename,
|
||||
tmp_file_prefix, tmp_file_prefix_length)) {
|
||||
/* Ignore errors for #sql tablespaces. */
|
||||
mem_free(tablename);
|
||||
if (remote.filepath) {
|
||||
mem_free(remote.filepath);
|
||||
}
|
||||
if (def.filepath) {
|
||||
mem_free(def.filepath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
no_good_file:
|
||||
fprintf(stderr,
|
||||
"InnoDB: We do not continue the crash recovery,"
|
||||
|
|
@ -4075,10 +4212,12 @@ no_good_file:
|
|||
" recovery here.\n");
|
||||
will_not_choose:
|
||||
mem_free(tablename);
|
||||
if (remote.success) {
|
||||
if (remote.filepath) {
|
||||
mem_free(remote.filepath);
|
||||
}
|
||||
if (def.filepath) {
|
||||
mem_free(def.filepath);
|
||||
}
|
||||
|
||||
if (srv_force_recovery > 0) {
|
||||
ib_logf(IB_LOG_LEVEL_INFO,
|
||||
|
|
@ -4089,9 +4228,6 @@ will_not_choose:
|
|||
return;
|
||||
}
|
||||
|
||||
/* If debug code, cause a core dump and call stack. For
|
||||
release builds just exit and rely on the messages above. */
|
||||
ut_ad(0);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
|
@ -4167,7 +4303,7 @@ will_not_choose:
|
|||
new_path = fil_make_ibbackup_old_name(fsp->filepath);
|
||||
|
||||
bool success = os_file_rename(
|
||||
innodb_file_data_key, fsp->filepath, new_path));
|
||||
innodb_file_data_key, fsp->filepath, new_path);
|
||||
|
||||
ut_a(success);
|
||||
|
||||
|
|
@ -4772,7 +4908,13 @@ retry:
|
|||
goto retry;
|
||||
}
|
||||
|
||||
fil_node_prepare_for_io(node, fil_system, space);
|
||||
if (!fil_node_prepare_for_io(node, fil_system, space)) {
|
||||
/* The tablespace data file, such as .ibd file, is missing */
|
||||
node->being_extended = false;
|
||||
mutex_exit(&fil_system->mutex);
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* At this point it is safe to release fil_system mutex. No
|
||||
other thread can rename, delete or close the file because
|
||||
|
|
@ -5044,9 +5186,10 @@ NOTE: you must call fil_mutex_enter_and_prepare_for_io() first!
|
|||
Prepares a file node for i/o. Opens the file if it is closed. Updates the
|
||||
pending i/o's field in the node and the system appropriately. Takes the node
|
||||
off the LRU list if it is in the LRU list. The caller must hold the fil_sys
|
||||
mutex. */
|
||||
mutex.
|
||||
@return false if the file can't be opened, otherwise true */
|
||||
static
|
||||
void
|
||||
bool
|
||||
fil_node_prepare_for_io(
|
||||
/*====================*/
|
||||
fil_node_t* node, /*!< in: file node */
|
||||
|
|
@ -5068,7 +5211,10 @@ fil_node_prepare_for_io(
|
|||
if (node->open == FALSE) {
|
||||
/* File is closed: open it */
|
||||
ut_a(node->n_pending == 0);
|
||||
fil_node_open_file(node, system, space);
|
||||
|
||||
if (!fil_node_open_file(node, system, space)) {
|
||||
return(false);
|
||||
}
|
||||
}
|
||||
|
||||
if (node->n_pending == 0 && fil_space_belongs_in_lru(space)) {
|
||||
|
|
@ -5080,6 +5226,8 @@ fil_node_prepare_for_io(
|
|||
}
|
||||
|
||||
node->n_pending++;
|
||||
|
||||
return(true);
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
|
|
@ -5177,7 +5325,7 @@ fil_io(
|
|||
because i/os are not actually handled until
|
||||
all have been posted: use with great
|
||||
caution! */
|
||||
ibool sync, /*!< in: TRUE if synchronous aio is desired */
|
||||
bool sync, /*!< in: true if synchronous aio is desired */
|
||||
ulint space_id, /*!< in: space id */
|
||||
ulint zip_size, /*!< in: compressed page size in bytes;
|
||||
0 for uncompressed pages */
|
||||
|
|
@ -5312,7 +5460,28 @@ fil_io(
|
|||
}
|
||||
|
||||
/* Open file if closed */
|
||||
fil_node_prepare_for_io(node, fil_system, space);
|
||||
if (!fil_node_prepare_for_io(node, fil_system, space)) {
|
||||
if (space->purpose == FIL_TABLESPACE
|
||||
&& fil_is_user_tablespace_id(space->id)) {
|
||||
mutex_exit(&fil_system->mutex);
|
||||
|
||||
ib_logf(IB_LOG_LEVEL_ERROR,
|
||||
"Trying to do i/o to a tablespace which "
|
||||
"exists without .ibd data file. "
|
||||
"i/o type %lu, space id %lu, page no %lu, "
|
||||
"i/o length %lu bytes",
|
||||
(ulong) type, (ulong) space_id,
|
||||
(ulong) block_offset, (ulong) len);
|
||||
|
||||
return(DB_TABLESPACE_DELETED);
|
||||
}
|
||||
|
||||
/* The tablespace is for log. Currently, we just assert here
|
||||
to prevent handling errors along the way fil_io returns.
|
||||
Also, if the log files are missing, it would be hard to
|
||||
promise the server can continue running. */
|
||||
ut_a(0);
|
||||
}
|
||||
|
||||
/* Check that at least the start offset is within the bounds of a
|
||||
single-table tablespace, including rollback tablespaces. */
|
||||
|
|
@ -5475,7 +5644,7 @@ fil_flush(
|
|||
fil_space_t* space;
|
||||
fil_node_t* node;
|
||||
os_file_t file;
|
||||
ib_int64_t old_mod_counter;
|
||||
|
||||
|
||||
mutex_enter(&fil_system->mutex);
|
||||
|
||||
|
|
@ -5511,16 +5680,18 @@ fil_flush(
|
|||
|
||||
space->n_pending_flushes++; /*!< prevent dropping of the space while
|
||||
we are flushing */
|
||||
node = UT_LIST_GET_FIRST(space->chain);
|
||||
for (node = UT_LIST_GET_FIRST(space->chain);
|
||||
node != NULL;
|
||||
node = UT_LIST_GET_NEXT(chain, node)) {
|
||||
|
||||
ib_int64_t old_mod_counter = node->modification_counter;;
|
||||
|
||||
if (old_mod_counter <= node->flush_counter) {
|
||||
continue;
|
||||
}
|
||||
|
||||
while (node) {
|
||||
if (node->modification_counter > node->flush_counter) {
|
||||
ut_a(node->open);
|
||||
|
||||
/* We want to flush the changes at least up to
|
||||
old_mod_counter */
|
||||
old_mod_counter = node->modification_counter;
|
||||
|
||||
if (space->purpose == FIL_TABLESPACE) {
|
||||
fil_n_pending_tablespace_flushes++;
|
||||
} else {
|
||||
|
|
@ -5538,11 +5709,14 @@ retry:
|
|||
/* We want to avoid calling os_file_flush() on
|
||||
the file twice at the same time, because we do
|
||||
not know what bugs OS's may contain in file
|
||||
i/o; sleep for a while */
|
||||
i/o */
|
||||
|
||||
ib_int64_t sig_count =
|
||||
os_event_reset(node->sync_event);
|
||||
|
||||
mutex_exit(&fil_system->mutex);
|
||||
|
||||
os_thread_sleep(20000);
|
||||
os_event_wait_low(node->sync_event, sig_count);
|
||||
|
||||
mutex_enter(&fil_system->mutex);
|
||||
|
||||
|
|
@ -5560,13 +5734,12 @@ retry:
|
|||
|
||||
mutex_exit(&fil_system->mutex);
|
||||
|
||||
/* fprintf(stderr, "Flushing to file %s\n",
|
||||
node->name); */
|
||||
|
||||
os_file_flush(file);
|
||||
|
||||
mutex_enter(&fil_system->mutex);
|
||||
|
||||
os_event_set(node->sync_event);
|
||||
|
||||
node->n_pending_flushes--;
|
||||
skip_flush:
|
||||
if (node->flush_counter < old_mod_counter) {
|
||||
|
|
@ -5591,9 +5764,6 @@ skip_flush:
|
|||
}
|
||||
}
|
||||
|
||||
node = UT_LIST_GET_NEXT(chain, node);
|
||||
}
|
||||
|
||||
space->n_pending_flushes--;
|
||||
|
||||
mutex_exit(&fil_system->mutex);
|
||||
|
|
@ -6131,11 +6301,11 @@ fil_delete_file(
|
|||
|
||||
ib_logf(IB_LOG_LEVEL_INFO, "Deleting %s", ibd_name);
|
||||
|
||||
os_file_delete_if_exists(ibd_name);
|
||||
os_file_delete_if_exists(innodb_file_data_key, ibd_name);
|
||||
|
||||
char* cfg_name = fil_make_cfg_name(ibd_name);
|
||||
|
||||
os_file_delete_if_exists(cfg_name);
|
||||
os_file_delete_if_exists(innodb_file_data_key, cfg_name);
|
||||
|
||||
mem_free(cfg_name);
|
||||
}
|
||||
|
|
@ -6198,15 +6368,17 @@ fil_mtr_rename_log(
|
|||
ulint new_space_id, /*!< in: tablespace id of the new
|
||||
table */
|
||||
const char* new_name, /*!< in: new table name */
|
||||
const char* tmp_name) /*!< in: temp table name used while
|
||||
const char* tmp_name, /*!< in: temp table name used while
|
||||
swapping */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
{
|
||||
mtr_t mtr;
|
||||
mtr_start(&mtr);
|
||||
if (old_space_id != TRX_SYS_SPACE) {
|
||||
fil_op_write_log(MLOG_FILE_RENAME, old_space_id,
|
||||
0, 0, old_name, tmp_name, &mtr);
|
||||
fil_op_write_log(MLOG_FILE_RENAME, new_space_id,
|
||||
0, 0, new_name, old_name, &mtr);
|
||||
mtr_commit(&mtr);
|
||||
}
|
||||
0, 0, old_name, tmp_name, mtr);
|
||||
}
|
||||
|
||||
if (new_space_id != TRX_SYS_SPACE) {
|
||||
fil_op_write_log(MLOG_FILE_RENAME, new_space_id,
|
||||
0, 0, new_name, old_name, mtr);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -1035,6 +1035,11 @@ fsp_try_extend_data_file(
|
|||
|
||||
success = fil_extend_space_to_desired_size(&actual_size, space,
|
||||
size + size_increase);
|
||||
if (!success) {
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
/* We ignore any fragments of a full megabyte when storing the size
|
||||
to the space header */
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2007, 2013, 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
|
||||
|
|
@ -26,6 +26,18 @@ Created 2007/3/16 Sunny Bains.
|
|||
#include "mem0mem.h"
|
||||
#include "fts0ast.h"
|
||||
#include "fts0pars.h"
|
||||
#include "fts0fts.h"
|
||||
|
||||
/* The FTS ast visit pass. */
|
||||
enum fts_ast_visit_pass_t {
|
||||
FTS_PASS_FIRST, /*!< First visit pass,
|
||||
process operators excluding
|
||||
FTS_EXIST and FTS_IGNORE */
|
||||
FTS_PASS_EXIST, /*!< Exist visit pass,
|
||||
process operator FTS_EXIST */
|
||||
FTS_PASS_IGNORE /*!< Ignore visit pass,
|
||||
process operator FTS_IGNORE */
|
||||
};
|
||||
|
||||
/******************************************************************//**
|
||||
Create an empty fts_ast_node_t.
|
||||
|
|
@ -66,7 +78,7 @@ fts_ast_create_node_oper(
|
|||
/******************************************************************//**
|
||||
This function takes ownership of the ptr and is responsible
|
||||
for free'ing it
|
||||
@return new node */
|
||||
@return new node or a node list with tokenized words */
|
||||
UNIV_INTERN
|
||||
fts_ast_node_t*
|
||||
fts_ast_create_node_term(
|
||||
|
|
@ -74,17 +86,68 @@ fts_ast_create_node_term(
|
|||
void* arg, /*!< in: ast state instance */
|
||||
const char* ptr) /*!< in: ast term string */
|
||||
{
|
||||
fts_ast_state_t* state = static_cast<fts_ast_state_t*>(arg);
|
||||
ulint len = strlen(ptr);
|
||||
fts_ast_node_t* node = fts_ast_node_create();
|
||||
ulint cur_pos = 0;
|
||||
fts_ast_node_t* node = NULL;
|
||||
fts_ast_node_t* node_list = NULL;
|
||||
fts_ast_node_t* first_node = NULL;
|
||||
|
||||
/* Scan the incoming string and filter out any "non-word" characters */
|
||||
while (cur_pos < len) {
|
||||
fts_string_t str;
|
||||
ulint offset;
|
||||
ulint cur_len;
|
||||
|
||||
cur_len = innobase_mysql_fts_get_token(
|
||||
state->charset,
|
||||
reinterpret_cast<const byte*>(ptr) + cur_pos,
|
||||
reinterpret_cast<const byte*>(ptr) + len, &str, &offset);
|
||||
|
||||
if (cur_len == 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
cur_pos += cur_len;
|
||||
|
||||
if (str.f_n_char > 0) {
|
||||
/* If the subsequent term (after the first one)'s size
|
||||
is less than fts_min_token_size, we shall ignore
|
||||
that. This is to make consistent with MyISAM behavior */
|
||||
if (first_node && (str.f_n_char < fts_min_token_size)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
node = fts_ast_node_create();
|
||||
|
||||
node->type = FTS_AST_TERM;
|
||||
|
||||
node->term.ptr = static_cast<byte*>(ut_malloc(len + 1));
|
||||
memcpy(node->term.ptr, ptr, len + 1);
|
||||
node->term.ptr = static_cast<byte*>(ut_malloc(
|
||||
str.f_len + 1));
|
||||
memcpy(node->term.ptr, str.f_str, str.f_len);
|
||||
node->term.ptr[str.f_len] = '\0';
|
||||
|
||||
fts_ast_state_add_node((fts_ast_state_t*) arg, node);
|
||||
fts_ast_state_add_node(
|
||||
static_cast<fts_ast_state_t*>(arg), node);
|
||||
|
||||
return(node);
|
||||
if (first_node) {
|
||||
/* There is more than one word, create
|
||||
a list to organize them */
|
||||
if (!node_list) {
|
||||
node_list = fts_ast_create_node_list(
|
||||
static_cast<fts_ast_state_t*>(
|
||||
arg),
|
||||
first_node);
|
||||
}
|
||||
|
||||
fts_ast_add_node(node_list, node);
|
||||
} else {
|
||||
first_node = node;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return((node_list != NULL) ? node_list : first_node);
|
||||
}
|
||||
|
||||
/******************************************************************//**
|
||||
|
|
@ -101,11 +164,19 @@ fts_ast_create_node_text(
|
|||
ulint len = strlen(ptr);
|
||||
fts_ast_node_t* node = NULL;
|
||||
|
||||
ut_ad(len >= 2);
|
||||
|
||||
ut_ad(len >= 1);
|
||||
|
||||
if (len <= 2) {
|
||||
/* There is a way to directly supply null terminator
|
||||
in the query string (by using 0x220022) and get here,
|
||||
and certainly it would not make a valid query text */
|
||||
ut_ad(ptr[0] == '\"');
|
||||
|
||||
if (len == 2) {
|
||||
ut_ad(ptr[0] == '\"');
|
||||
ut_ad(ptr[1] == '\"');
|
||||
}
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
|
|
@ -297,6 +368,16 @@ fts_ast_term_set_wildcard(
|
|||
fts_ast_node_t* node) /*!< in/out: set attribute of
|
||||
a term node */
|
||||
{
|
||||
if (!node) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* If it's a node list, the wildcard should be set to the tail node*/
|
||||
if (node->type == FTS_AST_LIST) {
|
||||
ut_ad(node->list.tail != NULL);
|
||||
node = node->list.tail;
|
||||
}
|
||||
|
||||
ut_a(node->type == FTS_AST_TERM);
|
||||
ut_a(!node->term.wildcard);
|
||||
|
||||
|
|
@ -393,9 +474,9 @@ fts_ast_node_print(
|
|||
}
|
||||
|
||||
/******************************************************************//**
|
||||
Traverse the AST - in-order traversal, except for the FTS_IGNORE
|
||||
nodes, which will be ignored in the first pass of each level, and
|
||||
visited in a second pass after all other nodes in the same level are visited.
|
||||
Traverse the AST - in-order traversal, except for the FTX_EXIST and FTS_IGNORE
|
||||
nodes, which will be ignored in the first pass of each level, and visited in a
|
||||
second and third pass after all other nodes in the same level are visited.
|
||||
@return DB_SUCCESS if all went well */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
|
|
@ -407,85 +488,142 @@ fts_ast_visit(
|
|||
void* arg, /*!< in: arg for callback */
|
||||
bool* has_ignore) /*!< out: true, if the operator
|
||||
was ignored during processing,
|
||||
currently we only ignore
|
||||
FTS_IGNORE operator */
|
||||
currently we ignore FTS_EXIST
|
||||
and FTS_IGNORE operators */
|
||||
{
|
||||
dberr_t error = DB_SUCCESS;
|
||||
fts_ast_node_t* oper_node = NULL;
|
||||
fts_ast_node_t* start_node;
|
||||
bool revisit = false;
|
||||
bool will_be_ignored = false;
|
||||
fts_ast_visit_pass_t visit_pass = FTS_PASS_FIRST;
|
||||
|
||||
start_node = node->list.head;
|
||||
|
||||
ut_a(node->type == FTS_AST_LIST
|
||||
|| node->type == FTS_AST_SUBEXP_LIST);
|
||||
|
||||
if (oper == FTS_EXIST_SKIP) {
|
||||
visit_pass = FTS_PASS_EXIST;
|
||||
} else if (oper == FTS_IGNORE_SKIP) {
|
||||
visit_pass = FTS_PASS_IGNORE;
|
||||
}
|
||||
|
||||
/* In the first pass of the tree, at the leaf level of the
|
||||
tree, FTS_IGNORE operation will be ignored. It will be
|
||||
repeated at the level above the leaf level */
|
||||
tree, FTS_EXIST and FTS_IGNORE operation will be ignored.
|
||||
It will be repeated at the level above the leaf level.
|
||||
|
||||
The basic idea here is that when we encounter FTS_EXIST or
|
||||
FTS_IGNORE, we will change the operator node into FTS_EXIST_SKIP
|
||||
or FTS_IGNORE_SKIP, and term node & text node with the operators
|
||||
is ignored in the first pass. We have two passes during the revisit:
|
||||
We process nodes with FTS_EXIST_SKIP in the exist pass, and then
|
||||
process nodes with FTS_IGNORE_SKIP in the ignore pass.
|
||||
|
||||
The order should be restrictly followed, or we will get wrong results.
|
||||
For example, we have a query 'a +b -c d +e -f'.
|
||||
first pass: process 'a' and 'd' by union;
|
||||
exist pass: process '+b' and '+e' by intersection;
|
||||
ignore pass: process '-c' and '-f' by difference. */
|
||||
|
||||
for (node = node->list.head;
|
||||
node && (error == DB_SUCCESS);
|
||||
node = node->next) {
|
||||
|
||||
if (node->type == FTS_AST_LIST) {
|
||||
switch(node->type) {
|
||||
case FTS_AST_LIST:
|
||||
if (visit_pass != FTS_PASS_FIRST) {
|
||||
break;
|
||||
}
|
||||
|
||||
error = fts_ast_visit(oper, node, visitor,
|
||||
arg, &will_be_ignored);
|
||||
|
||||
/* If will_be_ignored is set to true, then
|
||||
we encountered and ignored a FTS_IGNORE operator,
|
||||
and a second pass is needed to process FTS_IGNORE
|
||||
operator */
|
||||
we encountered and ignored a FTS_EXIST or FTS_IGNORE
|
||||
operator. */
|
||||
if (will_be_ignored) {
|
||||
revisit = true;
|
||||
/* Remember oper for list in case '-abc&def',
|
||||
ignored oper is from previous node of list.*/
|
||||
node->oper = oper;
|
||||
}
|
||||
} else if (node->type == FTS_AST_SUBEXP_LIST) {
|
||||
|
||||
break;
|
||||
|
||||
case FTS_AST_SUBEXP_LIST:
|
||||
if (visit_pass != FTS_PASS_FIRST) {
|
||||
break;
|
||||
}
|
||||
|
||||
error = fts_ast_visit_sub_exp(node, visitor, arg);
|
||||
} else if (node->type == FTS_AST_OPER) {
|
||||
break;
|
||||
|
||||
case FTS_AST_OPER:
|
||||
oper = node->oper;
|
||||
oper_node = node;
|
||||
} else {
|
||||
|
||||
/* Change the operator for revisit */
|
||||
if (oper == FTS_EXIST) {
|
||||
oper_node->oper = FTS_EXIST_SKIP;
|
||||
} else if (oper == FTS_IGNORE) {
|
||||
oper_node->oper = FTS_IGNORE_SKIP;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (node->visited) {
|
||||
continue;
|
||||
}
|
||||
|
||||
ut_a(oper == FTS_NONE || !oper_node
|
||||
|| oper_node->oper == oper);
|
||||
|| oper_node->oper == oper
|
||||
|| oper_node->oper == FTS_EXIST_SKIP
|
||||
|| oper_node->oper == FTS_IGNORE_SKIP);
|
||||
|
||||
if (oper == FTS_IGNORE) {
|
||||
if (oper== FTS_EXIST || oper == FTS_IGNORE) {
|
||||
*has_ignore = true;
|
||||
/* Change the operator to FTS_IGNORE_SKIP,
|
||||
so that it is processed in the second pass */
|
||||
oper_node->oper = FTS_IGNORE_SKIP;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (oper == FTS_IGNORE_SKIP) {
|
||||
/* This must be the second pass, now we process
|
||||
the FTS_IGNORE operator */
|
||||
visitor(FTS_IGNORE, node, arg);
|
||||
} else {
|
||||
visitor(oper, node, arg);
|
||||
}
|
||||
|
||||
/* Process leaf node accroding to its pass.*/
|
||||
if (oper == FTS_EXIST_SKIP
|
||||
&& visit_pass == FTS_PASS_EXIST) {
|
||||
error = visitor(FTS_EXIST, node, arg);
|
||||
node->visited = true;
|
||||
} else if (oper == FTS_IGNORE_SKIP
|
||||
&& visit_pass == FTS_PASS_IGNORE) {
|
||||
error = visitor(FTS_IGNORE, node, arg);
|
||||
node->visited = true;
|
||||
} else if (visit_pass == FTS_PASS_FIRST) {
|
||||
error = visitor(oper, node, arg);
|
||||
node->visited = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Second pass to process the skipped FTS_IGNORE operation.
|
||||
It is only performed at the level above leaf level */
|
||||
if (revisit) {
|
||||
/* Exist pass processes the skipped FTS_EXIST operation. */
|
||||
for (node = start_node;
|
||||
node && error == DB_SUCCESS;
|
||||
node = node->next) {
|
||||
|
||||
if (node->type == FTS_AST_LIST
|
||||
&& node->oper != FTS_IGNORE) {
|
||||
error = fts_ast_visit(FTS_EXIST_SKIP, node,
|
||||
visitor, arg, &will_be_ignored);
|
||||
}
|
||||
}
|
||||
|
||||
/* Ignore pass processes the skipped FTS_IGNORE operation. */
|
||||
for (node = start_node;
|
||||
node && error == DB_SUCCESS;
|
||||
node = node->next) {
|
||||
|
||||
if (node->type == FTS_AST_LIST) {
|
||||
/* In this pass, it will process all those
|
||||
operators ignored in the first pass, and those
|
||||
whose operators are set to FTS_IGNORE_SKIP */
|
||||
error = fts_ast_visit(
|
||||
oper, node, visitor, arg,
|
||||
&will_be_ignored);
|
||||
error = fts_ast_visit(FTS_IGNORE_SKIP, node,
|
||||
visitor, arg, &will_be_ignored);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -305,9 +305,9 @@ YY_BUFFER_STATE fts0b_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner
|
|||
YY_BUFFER_STATE fts0b_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE fts0b_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
|
||||
|
||||
void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
void *fts0balloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
void *fts0brealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
void fts0bfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
|
||||
#define yy_new_buffer fts0b_create_buffer
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ typedef int yy_state_type;
|
|||
static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
|
||||
static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
|
||||
static int yy_get_next_buffer (yyscan_t yyscanner );
|
||||
static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
|
||||
/* Done after the current pattern has been matched and before the
|
||||
* corresponding action - sets up yytext.
|
||||
|
|
@ -579,11 +579,11 @@ extern int fts0bwrap (yyscan_t yyscanner );
|
|||
#endif
|
||||
|
||||
#ifndef yytext_ptr
|
||||
static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
|
||||
static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
|
||||
#endif
|
||||
|
||||
#ifdef YY_NEED_STRLEN
|
||||
static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
|
||||
static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_INPUT
|
||||
|
|
@ -1609,7 +1609,7 @@ YY_BUFFER_STATE fts0b_scan_bytes (yyconst char * yybytes, int _yybytes_len , y
|
|||
#define YY_EXIT_FAILURE 2
|
||||
#endif
|
||||
|
||||
static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
(void) fprintf( stderr, "%s\n", msg );
|
||||
exit( YY_EXIT_FAILURE );
|
||||
|
|
@ -1910,7 +1910,7 @@ int fts0blex_destroy (yyscan_t yyscanner)
|
|||
*/
|
||||
|
||||
#ifndef yytext_ptr
|
||||
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
register int i;
|
||||
for ( i = 0; i < n; ++i )
|
||||
|
|
@ -1919,7 +1919,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t y
|
|||
#endif
|
||||
|
||||
#ifdef YY_NEED_STRLEN
|
||||
static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
register int n;
|
||||
for ( n = 0; s[n]; ++n )
|
||||
|
|
@ -1929,12 +1929,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute
|
|||
}
|
||||
#endif
|
||||
|
||||
void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
void *fts0balloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
return (void *) malloc( size );
|
||||
}
|
||||
|
||||
void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
/* The cast to (char *) in the following accommodates both
|
||||
* implementations that use char* generic pointers, and those
|
||||
|
|
@ -1946,7 +1946,7 @@ void *fts0brealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attr
|
|||
return (void *) realloc( (char *) ptr, size );
|
||||
}
|
||||
|
||||
void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
void fts0bfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
free( (char *) ptr ); /* see fts0brealloc() for (char *) cast */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2007, 2013, 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
|
||||
|
|
@ -221,7 +221,7 @@ fts_config_set_value(
|
|||
|
||||
graph = fts_parse_sql(
|
||||
fts_table, info,
|
||||
"BEGIN UPDATE %s SET value = :value WHERE key = :name;");
|
||||
"BEGIN UPDATE \"%s\" SET value = :value WHERE key = :name;");
|
||||
|
||||
trx->op_info = "setting FTS config value";
|
||||
|
||||
|
|
@ -246,7 +246,7 @@ fts_config_set_value(
|
|||
graph = fts_parse_sql(
|
||||
fts_table, info,
|
||||
"BEGIN\n"
|
||||
"INSERT INTO %s VALUES(:name, :value);");
|
||||
"INSERT INTO \"%s\" VALUES(:name, :value);");
|
||||
|
||||
trx->op_info = "inserting FTS config value";
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2011, 2013, 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,17 @@ Full Text Search interface
|
|||
a configurable variable */
|
||||
UNIV_INTERN ulong fts_max_cache_size;
|
||||
|
||||
/** Whether the total memory used for FTS cache is exhausted, and we will
|
||||
need a sync to free some memory */
|
||||
UNIV_INTERN bool fts_need_sync = false;
|
||||
|
||||
/** Variable specifying the total memory allocated for FTS cache */
|
||||
UNIV_INTERN ulong fts_max_total_cache_size;
|
||||
|
||||
/** This is FTS result cache limit for each query and would be
|
||||
a configurable variable */
|
||||
UNIV_INTERN ulong fts_result_cache_limit;
|
||||
|
||||
/** Variable specifying the maximum FTS max token size */
|
||||
UNIV_INTERN ulong fts_max_token_size;
|
||||
|
||||
|
|
@ -146,74 +157,65 @@ struct fts_aux_table_t {
|
|||
static const char* fts_create_common_tables_sql = {
|
||||
"BEGIN\n"
|
||||
""
|
||||
"CREATE TABLE %s_ADDED (\n"
|
||||
"CREATE TABLE \"%s_DELETED\" (\n"
|
||||
" doc_id BIGINT UNSIGNED\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON %s_ADDED(doc_id);\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON \"%s_DELETED\"(doc_id);\n"
|
||||
""
|
||||
"CREATE TABLE %s_DELETED (\n"
|
||||
" doc_id BIGINT UNSIGNED\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON %s_DELETED(doc_id);\n"
|
||||
""
|
||||
"CREATE TABLE %s_DELETED_CACHE (\n"
|
||||
"CREATE TABLE \"%s_DELETED_CACHE\" (\n"
|
||||
" doc_id BIGINT UNSIGNED\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND "
|
||||
"ON %s_DELETED_CACHE(doc_id);\n"
|
||||
"ON \"%s_DELETED_CACHE\"(doc_id);\n"
|
||||
""
|
||||
"CREATE TABLE %s_BEING_DELETED (\n"
|
||||
"CREATE TABLE \"%s_BEING_DELETED\" (\n"
|
||||
" doc_id BIGINT UNSIGNED\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND "
|
||||
"ON %s_BEING_DELETED(doc_id);\n"
|
||||
"ON \"%s_BEING_DELETED\"(doc_id);\n"
|
||||
""
|
||||
"CREATE TABLE %s_BEING_DELETED_CACHE (\n"
|
||||
"CREATE TABLE \"%s_BEING_DELETED_CACHE\" (\n"
|
||||
" doc_id BIGINT UNSIGNED\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND "
|
||||
"ON %s_BEING_DELETED_CACHE(doc_id);\n"
|
||||
"ON \"%s_BEING_DELETED_CACHE\"(doc_id);\n"
|
||||
""
|
||||
"CREATE TABLE %s_CONFIG (\n"
|
||||
"CREATE TABLE \"%s_CONFIG\" (\n"
|
||||
" key CHAR(50),\n"
|
||||
" value CHAR(50) NOT NULL\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON %s_CONFIG(key);\n"
|
||||
""
|
||||
"CREATE TABLE %s_STOPWORDS (\n"
|
||||
" word CHAR\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON %s_STOPWORDS(word);\n",
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON \"%s_CONFIG\"(key);\n"
|
||||
};
|
||||
|
||||
/** Template for creating the FTS auxiliary index specific tables. */
|
||||
#ifdef FTS_DOC_STATS_DEBUG
|
||||
/** Template for creating the FTS auxiliary index specific tables. This is
|
||||
mainly designed for the statistics work in the future */
|
||||
static const char* fts_create_index_tables_sql = {
|
||||
"BEGIN\n"
|
||||
""
|
||||
"CREATE TABLE %s_DOC_ID (\n"
|
||||
"CREATE TABLE \"%s_DOC_ID\" (\n"
|
||||
" doc_id BIGINT UNSIGNED,\n"
|
||||
" word_count INTEGER UNSIGNED NOT NULL\n"
|
||||
") COMPACT;\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON %s_DOC_ID(doc_id);\n"
|
||||
"CREATE UNIQUE CLUSTERED INDEX IND ON \"%s_DOC_ID\"(doc_id);\n"
|
||||
};
|
||||
#endif
|
||||
|
||||
/** Template for creating the ancillary FTS tables word index tables. */
|
||||
static const char* fts_create_index_sql = {
|
||||
"BEGIN\n"
|
||||
""
|
||||
"CREATE UNIQUE CLUSTERED INDEX FTS_INDEX_TABLE_IND "
|
||||
"ON %s(word, first_doc_id);\n"
|
||||
"ON \"%s\"(word, first_doc_id);\n"
|
||||
};
|
||||
|
||||
/** FTS auxiliary table suffixes that are common to all FT indexes. */
|
||||
static const char* fts_common_tables[] = {
|
||||
"ADDED",
|
||||
"BEING_DELETED",
|
||||
"BEING_DELETED_CACHE",
|
||||
"CONFIG",
|
||||
"DELETED",
|
||||
"DELETED_CACHE",
|
||||
"STOPWORDS",
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -232,19 +234,19 @@ const fts_index_selector_t fts_index_selector[] = {
|
|||
static const char* fts_config_table_insert_values_sql =
|
||||
"BEGIN\n"
|
||||
"\n"
|
||||
"INSERT INTO %s VALUES('"
|
||||
"INSERT INTO \"%s\" VALUES('"
|
||||
FTS_MAX_CACHE_SIZE_IN_MB "', '256');\n"
|
||||
""
|
||||
"INSERT INTO %s VALUES('"
|
||||
"INSERT INTO \"%s\" VALUES('"
|
||||
FTS_OPTIMIZE_LIMIT_IN_SECS "', '180');\n"
|
||||
""
|
||||
"INSERT INTO %s VALUES ('"
|
||||
"INSERT INTO \"%s\" VALUES ('"
|
||||
FTS_SYNCED_DOC_ID "', '0');\n"
|
||||
""
|
||||
"INSERT INTO %s VALUES ('"
|
||||
"INSERT INTO \"%s\" VALUES ('"
|
||||
FTS_TOTAL_DELETED_COUNT "', '0');\n"
|
||||
"" /* Note: 0 == FTS_TABLE_STATE_RUNNING */
|
||||
"INSERT INTO %s VALUES ('"
|
||||
"INSERT INTO \"%s\" VALUES ('"
|
||||
FTS_TABLE_STATE "', '0');\n";
|
||||
|
||||
/****************************************************************//**
|
||||
|
|
@ -355,6 +357,13 @@ fts_load_default_stopword(
|
|||
|
||||
allocator = stopword_info->heap;
|
||||
heap = static_cast<mem_heap_t*>(allocator->arg);
|
||||
|
||||
if (!stopword_info->cached_stopword) {
|
||||
/* For default stopword, we always use fts_utf8_string_cmp() */
|
||||
stopword_info->cached_stopword = rbt_create(
|
||||
sizeof(fts_tokenizer_word_t), fts_utf8_string_cmp);
|
||||
}
|
||||
|
||||
stop_words = stopword_info->cached_stopword;
|
||||
|
||||
str.f_n_char = 0;
|
||||
|
|
@ -468,9 +477,17 @@ fts_load_user_stopword(
|
|||
|
||||
/* Validate the user table existence and in the right
|
||||
format */
|
||||
if (!fts_valid_stopword_table(stopword_table_name)) {
|
||||
stopword_info->charset = fts_valid_stopword_table(stopword_table_name);
|
||||
if (!stopword_info->charset) {
|
||||
ret = FALSE;
|
||||
goto cleanup;
|
||||
} else if (!stopword_info->cached_stopword) {
|
||||
/* Create the stopword RB tree with the stopword column
|
||||
charset. All comparison will use this charset */
|
||||
stopword_info->cached_stopword = rbt_create_arg_cmp(
|
||||
sizeof(fts_tokenizer_word_t), innobase_fts_text_cmp,
|
||||
(void*)stopword_info->charset);
|
||||
|
||||
}
|
||||
|
||||
info = pars_info_create();
|
||||
|
|
@ -638,6 +655,8 @@ fts_cache_create(
|
|||
cache->sync_heap = ib_heap_allocator_create(heap);
|
||||
cache->sync_heap->arg = NULL;
|
||||
|
||||
fts_need_sync = false;
|
||||
|
||||
cache->sync = static_cast<fts_sync_t*>(
|
||||
mem_heap_zalloc(heap, sizeof(fts_sync_t)));
|
||||
|
||||
|
|
@ -649,10 +668,8 @@ fts_cache_create(
|
|||
|
||||
fts_cache_init(cache);
|
||||
|
||||
/* Create stopword RB tree. The stopword tree will
|
||||
remain in cache for the duration of FTS cache's lifetime */
|
||||
cache->stopword_info.cached_stopword = rbt_create(
|
||||
sizeof(fts_tokenizer_word_t), fts_utf8_string_cmp);
|
||||
cache->stopword_info.cached_stopword = NULL;
|
||||
cache->stopword_info.charset = NULL;
|
||||
|
||||
cache->stopword_info.heap = cache->self_heap;
|
||||
|
||||
|
|
@ -922,6 +939,8 @@ fts_que_graph_free_check_lock(
|
|||
mutex_enter(&dict_sys->mutex);
|
||||
}
|
||||
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
que_graph_free(graph);
|
||||
|
||||
if (!has_dict) {
|
||||
|
|
@ -1199,7 +1218,10 @@ fts_cache_destroy(
|
|||
mutex_free(&cache->optimize_lock);
|
||||
mutex_free(&cache->deleted_lock);
|
||||
mutex_free(&cache->doc_id_lock);
|
||||
|
||||
if (cache->stopword_info.cached_stopword) {
|
||||
rbt_free(cache->stopword_info.cached_stopword);
|
||||
}
|
||||
|
||||
if (cache->sync_heap->arg) {
|
||||
mem_heap_free(static_cast<mem_heap_t*>(cache->sync_heap->arg));
|
||||
|
|
@ -1500,6 +1522,112 @@ fts_drop_table(
|
|||
return(error);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Rename a single auxiliary table due to database name change.
|
||||
@return DB_SUCCESS or error code */
|
||||
static __attribute__((nonnull, warn_unused_result))
|
||||
dberr_t
|
||||
fts_rename_one_aux_table(
|
||||
/*=====================*/
|
||||
const char* new_name, /*!< in: new parent tbl name */
|
||||
const char* fts_table_old_name, /*!< in: old aux tbl name */
|
||||
trx_t* trx) /*!< in: transaction */
|
||||
{
|
||||
char fts_table_new_name[MAX_TABLE_NAME_LEN];
|
||||
ulint new_db_name_len = dict_get_db_name_len(new_name);
|
||||
ulint old_db_name_len = dict_get_db_name_len(fts_table_old_name);
|
||||
ulint table_new_name_len = strlen(fts_table_old_name)
|
||||
+ new_db_name_len - old_db_name_len;
|
||||
|
||||
/* Check if the new and old database names are the same, if so,
|
||||
nothing to do */
|
||||
ut_ad((new_db_name_len != old_db_name_len)
|
||||
|| strncmp(new_name, fts_table_old_name, old_db_name_len) != 0);
|
||||
|
||||
/* Get the database name from "new_name", and table name
|
||||
from the fts_table_old_name */
|
||||
strncpy(fts_table_new_name, new_name, new_db_name_len);
|
||||
strncpy(fts_table_new_name + new_db_name_len,
|
||||
strchr(fts_table_old_name, '/'),
|
||||
table_new_name_len - new_db_name_len);
|
||||
fts_table_new_name[table_new_name_len] = 0;
|
||||
|
||||
return(row_rename_table_for_mysql(
|
||||
fts_table_old_name, fts_table_new_name, trx, false));
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Rename auxiliary tables for all fts index for a table. This(rename)
|
||||
is due to database name change
|
||||
@return DB_SUCCESS or error code */
|
||||
|
||||
dberr_t
|
||||
fts_rename_aux_tables(
|
||||
/*==================*/
|
||||
dict_table_t* table, /*!< in: user Table */
|
||||
const char* new_name, /*!< in: new table name */
|
||||
trx_t* trx) /*!< in: transaction */
|
||||
{
|
||||
ulint i;
|
||||
fts_table_t fts_table;
|
||||
|
||||
FTS_INIT_FTS_TABLE(&fts_table, NULL, FTS_COMMON_TABLE, table);
|
||||
|
||||
/* Rename common auxiliary tables */
|
||||
for (i = 0; fts_common_tables[i] != NULL; ++i) {
|
||||
char* old_table_name;
|
||||
dberr_t err = DB_SUCCESS;
|
||||
|
||||
fts_table.suffix = fts_common_tables[i];
|
||||
|
||||
old_table_name = fts_get_table_name(&fts_table);
|
||||
|
||||
err = fts_rename_one_aux_table(new_name, old_table_name, trx);
|
||||
|
||||
mem_free(old_table_name);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
|
||||
fts_t* fts = table->fts;
|
||||
|
||||
/* Rename index specific auxiliary tables */
|
||||
for (i = 0; fts->indexes != 0 && i < ib_vector_size(fts->indexes);
|
||||
++i) {
|
||||
dict_index_t* index;
|
||||
|
||||
index = static_cast<dict_index_t*>(
|
||||
ib_vector_getp(fts->indexes, i));
|
||||
|
||||
FTS_INIT_INDEX_TABLE(&fts_table, NULL, FTS_INDEX_TABLE, index);
|
||||
|
||||
for (ulint j = 0; fts_index_selector[j].value; ++j) {
|
||||
dberr_t err;
|
||||
char* old_table_name;
|
||||
|
||||
fts_table.suffix = fts_get_suffix(j);
|
||||
|
||||
old_table_name = fts_get_table_name(&fts_table);
|
||||
|
||||
err = fts_rename_one_aux_table(
|
||||
new_name, old_table_name, trx);
|
||||
|
||||
DBUG_EXECUTE_IF("fts_rename_failure",
|
||||
err = DB_DEADLOCK;);
|
||||
|
||||
mem_free(old_table_name);
|
||||
|
||||
if (err != DB_SUCCESS) {
|
||||
return(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Drops the common ancillary tables needed for supporting an FTS index
|
||||
on the given table. row_mysql_lock_data_dictionary must have been called
|
||||
|
|
@ -1586,13 +1714,15 @@ fts_drop_index_tables(
|
|||
trx_t* trx, /*!< in: transaction */
|
||||
dict_index_t* index) /*!< in: Index to drop */
|
||||
{
|
||||
fts_table_t fts_table;
|
||||
dberr_t error = DB_SUCCESS;
|
||||
|
||||
#ifdef FTS_DOC_STATS_DEBUG
|
||||
fts_table_t fts_table;
|
||||
static const char* index_tables[] = {
|
||||
"DOC_ID",
|
||||
NULL
|
||||
};
|
||||
#endif /* FTS_DOC_STATS_DEBUG */
|
||||
|
||||
dberr_t err = fts_drop_index_split_tables(trx, index);
|
||||
|
||||
|
|
@ -1601,6 +1731,7 @@ fts_drop_index_tables(
|
|||
error = err;
|
||||
}
|
||||
|
||||
#ifdef FTS_DOC_STATS_DEBUG
|
||||
FTS_INIT_INDEX_TABLE(&fts_table, NULL, FTS_INDEX_TABLE, index);
|
||||
|
||||
for (ulint i = 0; index_tables[i] != NULL; ++i) {
|
||||
|
|
@ -1619,6 +1750,7 @@ fts_drop_index_tables(
|
|||
|
||||
mem_free(table_name);
|
||||
}
|
||||
#endif /* FTS_DOC_STATS_DEBUG */
|
||||
|
||||
return(error);
|
||||
}
|
||||
|
|
@ -1884,7 +2016,6 @@ fts_create_index_tables_low(
|
|||
|
||||
{
|
||||
ulint i;
|
||||
char* sql;
|
||||
que_t* graph;
|
||||
fts_table_t fts_table;
|
||||
dberr_t error = DB_SUCCESS;
|
||||
|
|
@ -1896,6 +2027,9 @@ fts_create_index_tables_low(
|
|||
fts_table.parent = table_name;
|
||||
fts_table.table = NULL;
|
||||
|
||||
#ifdef FTS_DOC_STATS_DEBUG
|
||||
char* sql;
|
||||
|
||||
/* Create the FTS auxiliary tables that are specific
|
||||
to an FTS index. */
|
||||
sql = fts_prepare_sql(&fts_table, fts_create_index_tables_sql);
|
||||
|
|
@ -1905,6 +2039,7 @@ fts_create_index_tables_low(
|
|||
|
||||
error = fts_eval_sql(trx, graph);
|
||||
que_graph_free(graph);
|
||||
#endif /* FTS_DOC_STATS_DEBUG */
|
||||
|
||||
for (i = 0; fts_index_selector[i].value && error == DB_SUCCESS; ++i) {
|
||||
dict_table_t* new_table;
|
||||
|
|
@ -2501,12 +2636,14 @@ fts_get_next_doc_id(
|
|||
|
||||
/* Otherwise, simply increment the value in cache */
|
||||
mutex_enter(&cache->doc_id_lock);
|
||||
++cache->next_doc_id;
|
||||
*doc_id = ++cache->next_doc_id;
|
||||
mutex_exit(&cache->doc_id_lock);
|
||||
} else {
|
||||
mutex_enter(&cache->doc_id_lock);
|
||||
*doc_id = cache->next_doc_id;
|
||||
mutex_exit(&cache->doc_id_lock);
|
||||
}
|
||||
|
||||
*doc_id = cache->next_doc_id;
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
@ -2555,7 +2692,7 @@ retry:
|
|||
graph = fts_parse_sql(
|
||||
&fts_table, info,
|
||||
"DECLARE FUNCTION my_func;\n"
|
||||
"DECLARE CURSOR c IS SELECT value FROM %s"
|
||||
"DECLARE CURSOR c IS SELECT value FROM \"%s\""
|
||||
" WHERE key = 'synced_doc_id' FOR UPDATE;\n"
|
||||
"BEGIN\n"
|
||||
""
|
||||
|
|
@ -2841,7 +2978,7 @@ fts_delete(
|
|||
graph = fts_parse_sql(
|
||||
&fts_table,
|
||||
info,
|
||||
"BEGIN INSERT INTO %s VALUES (:doc_id);");
|
||||
"BEGIN INSERT INTO \"%s\" VALUES (:doc_id);");
|
||||
|
||||
error = fts_eval_sql(trx, graph);
|
||||
|
||||
|
|
@ -3404,7 +3541,13 @@ fts_add_doc_by_id(
|
|||
|
||||
rw_lock_x_unlock(&table->fts->cache->lock);
|
||||
|
||||
if (cache->total_size > fts_max_cache_size) {
|
||||
DBUG_EXECUTE_IF(
|
||||
"fts_instrument_sync",
|
||||
fts_sync(cache->sync);
|
||||
);
|
||||
|
||||
if (cache->total_size > fts_max_cache_size
|
||||
|| fts_need_sync) {
|
||||
fts_sync(cache->sync);
|
||||
}
|
||||
|
||||
|
|
@ -3492,7 +3635,7 @@ fts_get_max_doc_id(
|
|||
btr_pcur_open_at_index_side(
|
||||
false, index, BTR_SEARCH_LEAF, &pcur, true, 0, &mtr);
|
||||
|
||||
if (page_get_n_recs(btr_pcur_get_page(&pcur)) > 0) {
|
||||
if (!page_is_empty(btr_pcur_get_page(&pcur))) {
|
||||
const rec_t* rec = NULL;
|
||||
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
ulint* offsets = offsets_;
|
||||
|
|
@ -3711,7 +3854,7 @@ fts_write_node(
|
|||
fts_table,
|
||||
info,
|
||||
"BEGIN\n"
|
||||
"INSERT INTO %s VALUES "
|
||||
"INSERT INTO \"%s\" VALUES "
|
||||
"(:token, :first_doc_id,"
|
||||
" :last_doc_id, :doc_count, :ilist);");
|
||||
}
|
||||
|
|
@ -3756,7 +3899,7 @@ fts_sync_add_deleted_cache(
|
|||
graph = fts_parse_sql(
|
||||
&fts_table,
|
||||
info,
|
||||
"BEGIN INSERT INTO %s VALUES (:doc_id);");
|
||||
"BEGIN INSERT INTO \"%s\" VALUES (:doc_id);");
|
||||
|
||||
for (i = 0; i < n_elems && error == DB_SUCCESS; ++i) {
|
||||
fts_update_t* update;
|
||||
|
|
@ -3937,7 +4080,7 @@ fts_sync_write_doc_stat(
|
|||
*graph = fts_parse_sql(
|
||||
&fts_table,
|
||||
info,
|
||||
"BEGIN INSERT INTO %s VALUES (:doc_id, :count);");
|
||||
"BEGIN INSERT INTO \"%s\" VALUES (:doc_id, :count);");
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
|
|
@ -4303,6 +4446,10 @@ fts_sync(
|
|||
}
|
||||
}
|
||||
|
||||
DBUG_EXECUTE_IF("fts_instrument_sync_interrupted",
|
||||
sync->interrupted = true;
|
||||
);
|
||||
|
||||
if (error == DB_SUCCESS && !sync->interrupted) {
|
||||
error = fts_sync_commit(sync);
|
||||
} else {
|
||||
|
|
@ -4553,7 +4700,7 @@ fts_get_docs_clear(
|
|||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
Get the initial Doc ID by consulting the ADDED and the CONFIG table
|
||||
Get the initial Doc ID by consulting the CONFIG table
|
||||
@return initial Doc ID */
|
||||
UNIV_INTERN
|
||||
doc_id_t
|
||||
|
|
@ -4656,7 +4803,7 @@ fts_get_rows_count(
|
|||
"DECLARE FUNCTION my_func;\n"
|
||||
"DECLARE CURSOR c IS"
|
||||
" SELECT COUNT(*) "
|
||||
" FROM %s;\n"
|
||||
" FROM \"%s\";\n"
|
||||
"BEGIN\n"
|
||||
"\n"
|
||||
"OPEN c;\n"
|
||||
|
|
@ -4892,20 +5039,20 @@ fts_get_doc_id_from_rec(
|
|||
ulint len;
|
||||
const byte* data;
|
||||
ulint col_no;
|
||||
ulint* offsets;
|
||||
doc_id_t doc_id = 0;
|
||||
dict_index_t* clust_index;
|
||||
ulint offsets_[REC_OFFS_NORMAL_SIZE];
|
||||
ulint* offsets = offsets_;
|
||||
mem_heap_t* my_heap = heap;
|
||||
|
||||
ut_a(table->fts->doc_col != ULINT_UNDEFINED);
|
||||
|
||||
offsets = offsets_;
|
||||
clust_index = dict_table_get_first_index(table);
|
||||
|
||||
offsets_[0] = UT_ARR_SIZE(offsets_);
|
||||
rec_offs_init(offsets_);
|
||||
|
||||
offsets = rec_get_offsets(
|
||||
rec, clust_index, offsets, ULINT_UNDEFINED, &heap);
|
||||
rec, clust_index, offsets, ULINT_UNDEFINED, &my_heap);
|
||||
|
||||
col_no = dict_col_get_clust_pos(
|
||||
&table->cols[table->fts->doc_col], clust_index);
|
||||
|
|
@ -4917,6 +5064,10 @@ fts_get_doc_id_from_rec(
|
|||
ut_ad(8 == sizeof(doc_id));
|
||||
doc_id = static_cast<doc_id_t>(mach_read_from_8(data));
|
||||
|
||||
if (my_heap && !heap) {
|
||||
mem_heap_free(my_heap);
|
||||
}
|
||||
|
||||
return(doc_id);
|
||||
}
|
||||
|
||||
|
|
@ -5794,7 +5945,7 @@ fts_check_and_drop_orphaned_tables(
|
|||
ib_vector_get(tables, i));
|
||||
|
||||
table = dict_table_open_on_id(
|
||||
aux_table->parent_id, TRUE, FALSE);
|
||||
aux_table->parent_id, TRUE, DICT_TABLE_OP_NORMAL);
|
||||
|
||||
if (table == NULL || table->fts == NULL) {
|
||||
|
||||
|
|
@ -5844,7 +5995,8 @@ fts_check_and_drop_orphaned_tables(
|
|||
path = fil_make_ibd_name(
|
||||
aux_table->name, false);
|
||||
|
||||
os_file_delete_if_exists(path);
|
||||
os_file_delete_if_exists(innodb_file_data_key,
|
||||
path);
|
||||
|
||||
mem_free(path);
|
||||
}
|
||||
|
|
@ -5995,18 +6147,19 @@ fts_drop_orphaned_tables(void)
|
|||
/**********************************************************************//**
|
||||
Check whether user supplied stopword table is of the right format.
|
||||
Caller is responsible to hold dictionary locks.
|
||||
@return TRUE if the table qualifies */
|
||||
@return the stopword column charset if qualifies */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
CHARSET_INFO*
|
||||
fts_valid_stopword_table(
|
||||
/*=====================*/
|
||||
const char* stopword_table_name) /*!< in: Stopword table
|
||||
name */
|
||||
{
|
||||
dict_table_t* table;
|
||||
dict_col_t* col = NULL;
|
||||
|
||||
if (!stopword_table_name) {
|
||||
return(FALSE);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
table = dict_table_get_low(stopword_table_name);
|
||||
|
|
@ -6016,9 +6169,8 @@ fts_valid_stopword_table(
|
|||
"InnoDB: user stopword table %s does not exist.\n",
|
||||
stopword_table_name);
|
||||
|
||||
return(FALSE);
|
||||
return(NULL);
|
||||
} else {
|
||||
dict_col_t* col;
|
||||
const char* col_name;
|
||||
|
||||
col_name = dict_table_get_col_name(table, 0);
|
||||
|
|
@ -6029,22 +6181,27 @@ fts_valid_stopword_table(
|
|||
"table %s. Its first column must be named as "
|
||||
"'value'.\n", stopword_table_name);
|
||||
|
||||
return(FALSE);
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
col = dict_table_get_nth_col(table, 0);
|
||||
|
||||
if (col->mtype != DATA_VARCHAR) {
|
||||
if (col->mtype != DATA_VARCHAR
|
||||
&& col->mtype != DATA_VARMYSQL) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: invalid column type for stopword "
|
||||
"table %s. Its first column must be of "
|
||||
"varchar type\n", stopword_table_name);
|
||||
|
||||
return(FALSE);
|
||||
return(NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
ut_ad(col);
|
||||
|
||||
return(innobase_get_fts_charset(
|
||||
static_cast<int>(col->prtype & DATA_MYSQL_TYPE_MASK),
|
||||
static_cast<ulint>(dtype_get_charset_coll(col->prtype))));
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
|
|
@ -6109,7 +6266,7 @@ fts_load_stopword(
|
|||
}
|
||||
|
||||
/* If stopword is turned off, no need to continue to load the
|
||||
stopword into cache */
|
||||
stopword into cache, but still need to do initialization */
|
||||
if (!use_stopword) {
|
||||
cache->stopword_info.status = STOPWORD_OFF;
|
||||
goto cleanup;
|
||||
|
|
@ -6166,6 +6323,11 @@ cleanup:
|
|||
trx_free_for_background(trx);
|
||||
}
|
||||
|
||||
if (!cache->stopword_info.cached_stopword) {
|
||||
cache->stopword_info.cached_stopword = rbt_create(
|
||||
sizeof(fts_tokenizer_word_t), fts_utf8_string_cmp);
|
||||
}
|
||||
|
||||
return(error == DB_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
@ -6329,7 +6491,6 @@ fts_init_index(
|
|||
dict_index_t* index;
|
||||
doc_id_t start_doc;
|
||||
fts_get_doc_t* get_doc = NULL;
|
||||
ibool has_fts = TRUE;
|
||||
fts_cache_t* cache = table->fts->cache;
|
||||
bool need_init = false;
|
||||
|
||||
|
|
@ -6367,11 +6528,15 @@ fts_init_index(
|
|||
|
||||
ut_a(index);
|
||||
|
||||
has_fts = FALSE;
|
||||
fts_doc_fetch_by_doc_id(NULL, start_doc, index,
|
||||
FTS_FETCH_DOC_BY_ID_LARGE,
|
||||
fts_init_get_doc_id, cache);
|
||||
} else {
|
||||
if (table->fts->cache->stopword_info.status
|
||||
& STOPWORD_NOT_INIT) {
|
||||
fts_load_stopword(table, NULL, NULL, NULL, TRUE, TRUE);
|
||||
}
|
||||
|
||||
for (ulint i = 0; i < ib_vector_size(cache->get_docs); ++i) {
|
||||
get_doc = static_cast<fts_get_doc_t*>(
|
||||
ib_vector_get(cache->get_docs, i));
|
||||
|
|
@ -6384,13 +6549,6 @@ fts_init_index(
|
|||
}
|
||||
}
|
||||
|
||||
if (has_fts) {
|
||||
if (table->fts->cache->stopword_info.status
|
||||
& STOPWORD_NOT_INIT) {
|
||||
fts_load_stopword(table, NULL, NULL, NULL, TRUE, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
table->fts->fts_status |= ADDED_TABLE_SYNCED;
|
||||
|
||||
fts_get_docs_clear(cache->get_docs);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2007, 2013, 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,9 @@ static const ulint FTS_OPTIMIZE_INTERVAL_IN_SECS = 300;
|
|||
/** Server is shutting down, so does we exiting the optimize thread */
|
||||
static bool fts_opt_start_shutdown = false;
|
||||
|
||||
/** Last time we did check whether system need a sync */
|
||||
static ib_time_t last_check_sync_time;
|
||||
|
||||
#if 0
|
||||
/** Check each table in round robin to see whether they'd
|
||||
need to be "optimized" */
|
||||
|
|
@ -242,22 +245,22 @@ static const char* fts_init_delete_sql =
|
|||
"BEGIN\n"
|
||||
"\n"
|
||||
"INSERT INTO %s_BEING_DELETED\n"
|
||||
"SELECT doc_id FROM %s_DELETED;\n"
|
||||
"SELECT doc_id FROM \"%s_DELETED\";\n"
|
||||
"\n"
|
||||
"INSERT INTO %s_BEING_DELETED_CACHE\n"
|
||||
"SELECT doc_id FROM %s_DELETED_CACHE;\n";
|
||||
"SELECT doc_id FROM \"%s_DELETED_CACHE\";\n";
|
||||
|
||||
static const char* fts_delete_doc_ids_sql =
|
||||
"BEGIN\n"
|
||||
"\n"
|
||||
"DELETE FROM %s_DELETED WHERE doc_id = :doc_id1;\n"
|
||||
"DELETE FROM %s_DELETED_CACHE WHERE doc_id = :doc_id2;\n";
|
||||
"DELETE FROM \"%s_DELETED\" WHERE doc_id = :doc_id1;\n"
|
||||
"DELETE FROM \"%s_DELETED_CACHE\" WHERE doc_id = :doc_id2;\n";
|
||||
|
||||
static const char* fts_end_delete_sql =
|
||||
"BEGIN\n"
|
||||
"\n"
|
||||
"DELETE FROM %s_BEING_DELETED;\n"
|
||||
"DELETE FROM %s_BEING_DELETED_CACHE;\n";
|
||||
"DELETE FROM \"%s_BEING_DELETED\";\n"
|
||||
"DELETE FROM \"%s_BEING_DELETED_CACHE\";\n";
|
||||
|
||||
/**********************************************************************//**
|
||||
Initialize fts_zip_t. */
|
||||
|
|
@ -500,7 +503,7 @@ fts_index_fetch_nodes(
|
|||
"DECLARE CURSOR c IS"
|
||||
" SELECT word, doc_count, first_doc_id, last_doc_id, "
|
||||
"ilist\n"
|
||||
" FROM %s\n"
|
||||
" FROM \"%s\"\n"
|
||||
" WHERE word LIKE :word\n"
|
||||
" ORDER BY first_doc_id;\n"
|
||||
"BEGIN\n"
|
||||
|
|
@ -824,7 +827,7 @@ fts_index_fetch_words(
|
|||
"DECLARE FUNCTION my_func;\n"
|
||||
"DECLARE CURSOR c IS"
|
||||
" SELECT word\n"
|
||||
" FROM %s\n"
|
||||
" FROM \"%s\"\n"
|
||||
" WHERE word > :word\n"
|
||||
" ORDER BY word;\n"
|
||||
"BEGIN\n"
|
||||
|
|
@ -984,7 +987,7 @@ fts_table_fetch_doc_ids(
|
|||
info,
|
||||
"DECLARE FUNCTION my_func;\n"
|
||||
"DECLARE CURSOR c IS"
|
||||
" SELECT doc_id FROM %s;\n"
|
||||
" SELECT doc_id FROM \"%s\";\n"
|
||||
"BEGIN\n"
|
||||
"\n"
|
||||
"OPEN c;\n"
|
||||
|
|
@ -1457,7 +1460,7 @@ fts_optimize_write_word(
|
|||
graph = fts_parse_sql(
|
||||
fts_table,
|
||||
info,
|
||||
"BEGIN DELETE FROM %s WHERE word = :word;");
|
||||
"BEGIN DELETE FROM \"%s\" WHERE word = :word;");
|
||||
|
||||
error = fts_eval_sql(trx, graph);
|
||||
|
||||
|
|
@ -2813,6 +2816,43 @@ fts_optimize_how_many(
|
|||
return(n_tables);
|
||||
}
|
||||
|
||||
/**********************************************************************//**
|
||||
Check if the total memory used by all FTS table exceeds the maximum limit.
|
||||
@return true if a sync is needed, false otherwise */
|
||||
static
|
||||
bool
|
||||
fts_is_sync_needed(
|
||||
/*===============*/
|
||||
const ib_vector_t* tables) /*!< in: registered tables
|
||||
vector*/
|
||||
{
|
||||
ulint total_memory = 0;
|
||||
double time_diff = difftime(ut_time(), last_check_sync_time);
|
||||
|
||||
if (fts_need_sync || time_diff < 5) {
|
||||
return(false);
|
||||
}
|
||||
|
||||
last_check_sync_time = ut_time();
|
||||
|
||||
for (ulint i = 0; i < ib_vector_size(tables); ++i) {
|
||||
const fts_slot_t* slot;
|
||||
|
||||
slot = static_cast<const fts_slot_t*>(
|
||||
ib_vector_get_const(tables, i));
|
||||
|
||||
if (slot->table && slot->table->fts) {
|
||||
total_memory += slot->table->fts->cache->total_size;
|
||||
}
|
||||
|
||||
if (total_memory > fts_max_total_cache_size) {
|
||||
return(true);
|
||||
}
|
||||
}
|
||||
|
||||
return(false);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/*********************************************************************//**
|
||||
Check whether a table needs to be optimized. */
|
||||
|
|
@ -2933,6 +2973,10 @@ fts_optimize_thread(
|
|||
|
||||
/* Timeout ? */
|
||||
if (msg == NULL) {
|
||||
if (fts_is_sync_needed(tables)) {
|
||||
fts_need_sync = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
@ -3055,6 +3099,7 @@ fts_optimize_init(void)
|
|||
|
||||
fts_optimize_wq = ib_wqueue_create();
|
||||
ut_a(fts_optimize_wq != NULL);
|
||||
last_check_sync_time = ut_time();
|
||||
|
||||
os_thread_create(fts_optimize_thread, fts_optimize_wq, NULL);
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2007, 2013, 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
|
||||
|
|
@ -193,6 +193,10 @@ term : FTS_TERM {
|
|||
free($1);
|
||||
}
|
||||
|
||||
/* Ignore leading '*' */
|
||||
| '*' term {
|
||||
$$ = $2;
|
||||
}
|
||||
;
|
||||
|
||||
text : FTS_TEXT {
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -305,9 +305,9 @@ YY_BUFFER_STATE fts0t_scan_buffer (char *base,yy_size_t size ,yyscan_t yyscanner
|
|||
YY_BUFFER_STATE fts0t_scan_string (yyconst char *yy_str ,yyscan_t yyscanner );
|
||||
YY_BUFFER_STATE fts0t_scan_bytes (yyconst char *bytes,int len ,yyscan_t yyscanner );
|
||||
|
||||
void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) );
|
||||
void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) );
|
||||
void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) );
|
||||
void *fts0talloc (yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
void *fts0trealloc (void *,yy_size_t , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
void fts0tfree (void * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
|
||||
#define yy_new_buffer fts0t_create_buffer
|
||||
|
||||
|
|
@ -347,7 +347,7 @@ typedef int yy_state_type;
|
|||
static yy_state_type yy_get_previous_state (yyscan_t yyscanner );
|
||||
static yy_state_type yy_try_NUL_trans (yy_state_type current_state ,yyscan_t yyscanner);
|
||||
static int yy_get_next_buffer (yyscan_t yyscanner );
|
||||
static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) );
|
||||
static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) );
|
||||
|
||||
/* Done after the current pattern has been matched and before the
|
||||
* corresponding action - sets up yytext.
|
||||
|
|
@ -359,8 +359,8 @@ static void yy_fatal_error (yyconst char msg[] , yyscan_t yyscanner __attribute_
|
|||
*yy_cp = '\0'; \
|
||||
yyg->yy_c_buf_p = yy_cp;
|
||||
|
||||
#define YY_NUM_RULES 6
|
||||
#define YY_END_OF_BUFFER 7
|
||||
#define YY_NUM_RULES 7
|
||||
#define YY_END_OF_BUFFER 8
|
||||
/* This struct is not used in this scanner,
|
||||
but its presence is necessary. */
|
||||
struct yy_trans_info
|
||||
|
|
@ -370,7 +370,7 @@ struct yy_trans_info
|
|||
};
|
||||
static yyconst flex_int16_t yy_accept[17] =
|
||||
{ 0,
|
||||
4, 4, 7, 4, 1, 5, 1, 6, 6, 2,
|
||||
4, 4, 8, 4, 1, 6, 1, 5, 5, 2,
|
||||
4, 1, 1, 0, 3, 0
|
||||
} ;
|
||||
|
||||
|
|
@ -575,11 +575,11 @@ extern int fts0twrap (yyscan_t yyscanner );
|
|||
#endif
|
||||
|
||||
#ifndef yytext_ptr
|
||||
static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)));
|
||||
static void yy_flex_strncpy (char *,yyconst char *,int , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
|
||||
#endif
|
||||
|
||||
#ifdef YY_NEED_STRLEN
|
||||
static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)));
|
||||
static int yy_flex_strlen (yyconst char * , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)));
|
||||
#endif
|
||||
|
||||
#ifndef YY_NO_INPUT
|
||||
|
|
@ -816,17 +816,22 @@ YY_RULE_SETUP
|
|||
}
|
||||
YY_BREAK
|
||||
case 5:
|
||||
/* rule 5 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 65 "fts0tlex.l"
|
||||
;
|
||||
YY_BREAK
|
||||
case 6:
|
||||
/* rule 6 can match eol */
|
||||
YY_RULE_SETUP
|
||||
#line 66 "fts0tlex.l"
|
||||
|
||||
YY_BREAK
|
||||
case 6:
|
||||
case 7:
|
||||
YY_RULE_SETUP
|
||||
#line 68 "fts0tlex.l"
|
||||
ECHO;
|
||||
YY_BREAK
|
||||
#line 829 "fts0tlex.cc"
|
||||
#line 834 "fts0tlex.cc"
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
yyterminate();
|
||||
|
||||
|
|
@ -1596,7 +1601,7 @@ YY_BUFFER_STATE fts0t_scan_bytes (yyconst char * yybytes, int _yybytes_len , y
|
|||
#define YY_EXIT_FAILURE 2
|
||||
#endif
|
||||
|
||||
static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)))
|
||||
static void yy_fatal_error (yyconst char* msg , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
(void) fprintf( stderr, "%s\n", msg );
|
||||
exit( YY_EXIT_FAILURE );
|
||||
|
|
@ -1897,7 +1902,7 @@ int fts0tlex_destroy (yyscan_t yyscanner)
|
|||
*/
|
||||
|
||||
#ifndef yytext_ptr
|
||||
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)))
|
||||
static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
register int i;
|
||||
for ( i = 0; i < n; ++i )
|
||||
|
|
@ -1906,7 +1911,7 @@ static void yy_flex_strncpy (char* s1, yyconst char * s2, int n , yyscan_t yysc
|
|||
#endif
|
||||
|
||||
#ifdef YY_NEED_STRLEN
|
||||
static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)))
|
||||
static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
register int n;
|
||||
for ( n = 0; s[n]; ++n )
|
||||
|
|
@ -1916,12 +1921,12 @@ static int yy_flex_strlen (yyconst char * s , yyscan_t yyscanner __attribute__(
|
|||
}
|
||||
#endif
|
||||
|
||||
void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)))
|
||||
void *fts0talloc (yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
return (void *) malloc( size );
|
||||
}
|
||||
|
||||
void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)))
|
||||
void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
/* The cast to (char *) in the following accommodates both
|
||||
* implementations that use char* generic pointers, and those
|
||||
|
|
@ -1933,7 +1938,7 @@ void *fts0trealloc (void * ptr, yy_size_t size , yyscan_t yyscanner __attribu
|
|||
return (void *) realloc( (char *) ptr, size );
|
||||
}
|
||||
|
||||
void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)))
|
||||
void fts0tfree (void * ptr , yyscan_t yyscanner __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)) __attribute__((unused)))
|
||||
{
|
||||
free( (char *) ptr ); /* see fts0trealloc() for (char *) cast */
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
|
|||
|
||||
return(FTS_TERM);
|
||||
}
|
||||
|
||||
. ;
|
||||
\n
|
||||
|
||||
%%
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2000, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2008, 2009 Google Inc.
|
||||
Copyright (c) 2009, Percona Inc.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
|
@ -154,8 +154,6 @@ static uint innobase_old_blocks_pct;
|
|||
of the buffer pool. */
|
||||
static uint innobase_change_buffer_max_size = CHANGE_BUFFER_DEFAULT_SIZE;
|
||||
|
||||
static ulong innobase_compression_level = DEFAULT_COMPRESSION_LEVEL;
|
||||
|
||||
/* The default values for the following char* start-up parameters
|
||||
are determined in innobase_init below: */
|
||||
|
||||
|
|
@ -396,7 +394,7 @@ static PSI_rwlock_info all_innodb_rwlocks[] = {
|
|||
{&index_tree_rw_lock_key, "index_tree_rw_lock", 0},
|
||||
{&index_online_log_key, "index_online_log", 0},
|
||||
{&dict_table_stats_latch_key, "dict_table_stats", 0},
|
||||
{&hash_table_rw_lock_key, "hash table locks", 0}
|
||||
{&hash_table_rw_lock_key, "hash_table_locks", 0}
|
||||
};
|
||||
# endif /* UNIV_PFS_RWLOCK */
|
||||
|
||||
|
|
@ -413,7 +411,7 @@ static PSI_thread_info all_innodb_threads[] = {
|
|||
{&srv_master_thread_key, "srv_master_thread", 0},
|
||||
{&srv_purge_thread_key, "srv_purge_thread", 0},
|
||||
{&buf_page_cleaner_thread_key, "page_cleaner_thread", 0},
|
||||
{&recv_writer_thread_key, "recovery writer thread", 0}
|
||||
{&recv_writer_thread_key, "recv_writer_thread", 0}
|
||||
};
|
||||
# endif /* UNIV_PFS_THREAD */
|
||||
|
||||
|
|
@ -453,10 +451,18 @@ ib_cb_t innodb_api_cb[] = {
|
|||
(ib_cb_t) ib_clust_read_tuple_create,
|
||||
(ib_cb_t) ib_tuple_delete,
|
||||
(ib_cb_t) ib_tuple_copy,
|
||||
(ib_cb_t) ib_tuple_read_u8,
|
||||
(ib_cb_t) ib_tuple_write_u8,
|
||||
(ib_cb_t) ib_tuple_read_u16,
|
||||
(ib_cb_t) ib_tuple_write_u16,
|
||||
(ib_cb_t) ib_tuple_read_u32,
|
||||
(ib_cb_t) ib_tuple_write_u32,
|
||||
(ib_cb_t) ib_tuple_read_u64,
|
||||
(ib_cb_t) ib_tuple_write_u64,
|
||||
(ib_cb_t) ib_tuple_read_i8,
|
||||
(ib_cb_t) ib_tuple_write_i8,
|
||||
(ib_cb_t) ib_tuple_read_i16,
|
||||
(ib_cb_t) ib_tuple_write_i16,
|
||||
(ib_cb_t) ib_tuple_read_i32,
|
||||
(ib_cb_t) ib_tuple_write_i32,
|
||||
(ib_cb_t) ib_tuple_read_i64,
|
||||
|
|
@ -511,6 +517,15 @@ innodb_stopword_table_validate(
|
|||
system clustered index when there is no primary key. */
|
||||
const char innobase_index_reserve_name[] = "GEN_CLUST_INDEX";
|
||||
|
||||
/******************************************************************//**
|
||||
Maps a MySQL trx isolation level code to the InnoDB isolation level code
|
||||
@return InnoDB isolation level */
|
||||
static inline
|
||||
ulint
|
||||
innobase_map_isolation_level(
|
||||
/*=========================*/
|
||||
enum_tx_isolation iso); /*!< in: MySQL isolation level code */
|
||||
|
||||
/******************************************************************//**
|
||||
Maps a MySQL trx isolation level code to the InnoDB isolation level code
|
||||
@return InnoDB isolation level */
|
||||
|
|
@ -1506,7 +1521,8 @@ convert_error_code_to_mysql(
|
|||
|
||||
case DB_FTS_INVALID_DOCID:
|
||||
return(HA_FTS_INVALID_DOCID);
|
||||
|
||||
case DB_FTS_EXCEED_RESULT_CACHE_LIMIT:
|
||||
return(HA_ERR_OUT_OF_MEM);
|
||||
case DB_TOO_MANY_CONCURRENT_TRXS:
|
||||
return(HA_ERR_TOO_MANY_CONCURRENT_TRXS);
|
||||
case DB_UNSUPPORTED:
|
||||
|
|
@ -1519,6 +1535,8 @@ convert_error_code_to_mysql(
|
|||
return(HA_ERR_OUT_OF_MEM);
|
||||
case DB_TABLESPACE_EXISTS:
|
||||
return(HA_ERR_TABLESPACE_EXISTS);
|
||||
case DB_IDENTIFIER_TOO_LONG:
|
||||
return(HA_ERR_INTERNAL_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1611,6 +1629,31 @@ innobase_convert_from_table_id(
|
|||
strconvert(cs, from, FN_REFLEN, &my_charset_filename, to, (uint) len, &errors);
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Check if the length of the identifier exceeds the maximum allowed.
|
||||
return true when length of identifier is too long. */
|
||||
UNIV_INTERN
|
||||
my_bool
|
||||
innobase_check_identifier_length(
|
||||
/*=============================*/
|
||||
const char* id) /* in: FK identifier to check excluding the
|
||||
database portion. */
|
||||
{
|
||||
int well_formed_error = 0;
|
||||
CHARSET_INFO *cs = system_charset_info;
|
||||
DBUG_ENTER("innobase_check_identifier_length");
|
||||
|
||||
uint res = cs->cset->well_formed_len(cs, id, id + strlen(id),
|
||||
NAME_CHAR_LEN,
|
||||
&well_formed_error);
|
||||
|
||||
if (well_formed_error || res == NAME_CHAR_LEN) {
|
||||
my_error(ER_TOO_LONG_IDENT, MYF(0), id);
|
||||
DBUG_RETURN(true);
|
||||
}
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
|
||||
/******************************************************************//**
|
||||
Converts an identifier to UTF-8. */
|
||||
UNIV_INTERN
|
||||
|
|
@ -1754,9 +1797,14 @@ innobase_mysql_tmpfile(void)
|
|||
/*========================*/
|
||||
{
|
||||
int fd2 = -1;
|
||||
File fd = mysql_tmpfile("ib");
|
||||
File fd;
|
||||
|
||||
DBUG_EXECUTE_IF("innobase_tmpfile_creation_failure", return(-1););
|
||||
DBUG_EXECUTE_IF(
|
||||
"innobase_tmpfile_creation_failure",
|
||||
return(-1);
|
||||
);
|
||||
|
||||
fd = mysql_tmpfile("ib");
|
||||
|
||||
if (fd >= 0) {
|
||||
/* Copy the file descriptor, so that the additional resources
|
||||
|
|
@ -2125,12 +2173,12 @@ void
|
|||
innobase_copy_frm_flags_from_create_info(
|
||||
/*=====================================*/
|
||||
dict_table_t* innodb_table, /*!< in/out: InnoDB table */
|
||||
HA_CREATE_INFO* create_info) /*!< in: create info */
|
||||
const HA_CREATE_INFO* create_info) /*!< in: create info */
|
||||
{
|
||||
ibool ps_on;
|
||||
ibool ps_off;
|
||||
|
||||
if (dict_table_is_temporary(innodb_table) || srv_read_only_mode) {
|
||||
if (dict_table_is_temporary(innodb_table)) {
|
||||
/* Temp tables do not use persistent stats. */
|
||||
ps_on = FALSE;
|
||||
ps_off = TRUE;
|
||||
|
|
@ -2161,12 +2209,12 @@ void
|
|||
innobase_copy_frm_flags_from_table_share(
|
||||
/*=====================================*/
|
||||
dict_table_t* innodb_table, /*!< in/out: InnoDB table */
|
||||
TABLE_SHARE* table_share) /*!< in: table share */
|
||||
const TABLE_SHARE* table_share) /*!< in: table share */
|
||||
{
|
||||
ibool ps_on;
|
||||
ibool ps_off;
|
||||
|
||||
if (dict_table_is_temporary(innodb_table) || srv_read_only_mode) {
|
||||
if (dict_table_is_temporary(innodb_table)) {
|
||||
/* Temp tables do not use persistent stats */
|
||||
ps_on = FALSE;
|
||||
ps_off = TRUE;
|
||||
|
|
@ -2229,6 +2277,10 @@ ha_innobase::update_thd(
|
|||
{
|
||||
trx_t* trx;
|
||||
|
||||
DBUG_ENTER("ha_innobase::update_thd");
|
||||
DBUG_PRINT("ha_innobase::update_thd", ("user_thd: %p -> %p",
|
||||
user_thd, thd));
|
||||
|
||||
/* The table should have been opened in ha_innobase::open(). */
|
||||
DBUG_ASSERT(prebuilt->table->n_ref_count > 0);
|
||||
|
||||
|
|
@ -2240,6 +2292,7 @@ ha_innobase::update_thd(
|
|||
}
|
||||
|
||||
user_thd = thd;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
|
@ -2479,21 +2532,18 @@ innobase_convert_identifier(
|
|||
ibool file_id)/*!< in: TRUE=id is a table or database name;
|
||||
FALSE=id is an UTF-8 string */
|
||||
{
|
||||
char nz[NAME_LEN + 1];
|
||||
char nz2[NAME_LEN + 1 + EXPLAIN_FILENAME_MAX_EXTRA_LENGTH];
|
||||
|
||||
const char* s = id;
|
||||
int q;
|
||||
|
||||
if (file_id) {
|
||||
|
||||
char nz[MAX_TABLE_NAME_LEN + 1];
|
||||
char nz2[MAX_TABLE_NAME_LEN + 1];
|
||||
|
||||
/* Decode the table name. The MySQL function expects
|
||||
a NUL-terminated string. The input and output strings
|
||||
buffers must not be shared. */
|
||||
|
||||
if (UNIV_UNLIKELY(idlen > (sizeof nz) - 1)) {
|
||||
idlen = (sizeof nz) - 1;
|
||||
}
|
||||
|
||||
ut_a(idlen <= MAX_TABLE_NAME_LEN);
|
||||
memcpy(nz, id, idlen);
|
||||
nz[idlen] = 0;
|
||||
|
||||
|
|
@ -2752,6 +2802,7 @@ ha_innobase::init_table_handle_for_HANDLER(void)
|
|||
Gives the file extension of an InnoDB single-table tablespace. */
|
||||
static const char* ha_innobase_exts[] = {
|
||||
".ibd",
|
||||
".isl",
|
||||
NullS
|
||||
};
|
||||
|
||||
|
|
@ -2922,14 +2973,33 @@ mem_free_and_error:
|
|||
|
||||
srv_normalize_path_for_win(srv_log_group_home_dir);
|
||||
|
||||
if (strchr(srv_log_group_home_dir, ';')
|
||||
|| innobase_mirrored_log_groups != 1) {
|
||||
sql_print_error("syntax error in innodb_log_group_home_dir, "
|
||||
"or a wrong number of mirrored log groups");
|
||||
|
||||
if (strchr(srv_log_group_home_dir, ';')) {
|
||||
sql_print_error("syntax error in innodb_log_group_home_dir");
|
||||
goto mem_free_and_error;
|
||||
}
|
||||
|
||||
if (innobase_mirrored_log_groups == 1) {
|
||||
sql_print_warning(
|
||||
"innodb_mirrored_log_groups is an unimplemented "
|
||||
"feature and the variable will be completely "
|
||||
"removed in a future version.");
|
||||
}
|
||||
|
||||
if (innobase_mirrored_log_groups > 1) {
|
||||
sql_print_error(
|
||||
"innodb_mirrored_log_groups is an unimplemented feature and "
|
||||
"the variable will be completely removed in a future version. "
|
||||
"Using values other than 1 is not supported.");
|
||||
goto mem_free_and_error;
|
||||
}
|
||||
|
||||
if (innobase_mirrored_log_groups == 0) {
|
||||
/* To throw a deprecation warning message when the option is
|
||||
passed, the default was changed to '0' (as a workaround). Since
|
||||
the only value accepted for this option is '1', reset it to 1 */
|
||||
innobase_mirrored_log_groups = 1;
|
||||
}
|
||||
|
||||
/* Validate the file format by animal name */
|
||||
if (innobase_file_format_name != NULL) {
|
||||
|
||||
|
|
@ -3134,8 +3204,6 @@ innobase_change_buffering_inited_ok:
|
|||
|
||||
srv_use_doublewrite_buf = (ibool) innobase_use_doublewrite;
|
||||
|
||||
page_compression_level = (ulint) innobase_compression_level;
|
||||
|
||||
if (!innobase_use_checksums) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
|
|
@ -3366,6 +3434,9 @@ innobase_end(
|
|||
mysql_mutex_destroy(&pending_checkpoint_mutex);
|
||||
}
|
||||
|
||||
my_free(fts_server_stopword_table);
|
||||
fts_server_stopword_table= NULL;
|
||||
|
||||
DBUG_RETURN(err);
|
||||
}
|
||||
|
||||
|
|
@ -4909,10 +4980,10 @@ ha_innobase::open(
|
|||
dict_table_t* ib_table;
|
||||
char norm_name[FN_REFLEN];
|
||||
THD* thd;
|
||||
ulint retries = 0;
|
||||
char* is_part = NULL;
|
||||
ibool par_case_name_set = FALSE;
|
||||
char par_case_name[FN_REFLEN];
|
||||
dict_err_ignore_t ignore_err = DICT_ERR_IGNORE_NONE;
|
||||
|
||||
DBUG_ENTER("ha_innobase::open");
|
||||
|
||||
|
|
@ -4942,20 +5013,22 @@ ha_innobase::open(
|
|||
upd_buf_size = 0;
|
||||
|
||||
/* We look for pattern #P# to see if the table is partitioned
|
||||
MySQL table. The retry logic for partitioned tables is a
|
||||
workaround for http://bugs.mysql.com/bug.php?id=33349. Look
|
||||
at support issue https://support.mysql.com/view.php?id=21080
|
||||
for more details. */
|
||||
MySQL table. */
|
||||
#ifdef __WIN__
|
||||
is_part = strstr(norm_name, "#p#");
|
||||
#else
|
||||
is_part = strstr(norm_name, "#P#");
|
||||
#endif /* __WIN__ */
|
||||
|
||||
retry:
|
||||
/* Check whether FOREIGN_KEY_CHECKS is set to 0. If so, the table
|
||||
can be opened even if some FK indexes are missing. If not, the table
|
||||
can't be opened in the same situation */
|
||||
if (thd_test_options(thd, OPTION_NO_FOREIGN_KEY_CHECKS)) {
|
||||
ignore_err = DICT_ERR_IGNORE_FK_NOKEY;
|
||||
}
|
||||
|
||||
/* Get pointer to a table object in InnoDB dictionary cache */
|
||||
ib_table = dict_table_open_on_name(norm_name, FALSE, TRUE,
|
||||
DICT_ERR_IGNORE_NONE);
|
||||
ib_table = dict_table_open_on_name(norm_name, FALSE, TRUE, ignore_err);
|
||||
|
||||
if (ib_table
|
||||
&& ((!DICT_TF2_FLAG_IS_SET(ib_table, DICT_TF2_FTS_HAS_DOC_ID)
|
||||
|
|
@ -4981,7 +5054,7 @@ retry:
|
|||
}
|
||||
|
||||
if (NULL == ib_table) {
|
||||
if (is_part && retries < 10) {
|
||||
if (is_part) {
|
||||
/* MySQL partition engine hard codes the file name
|
||||
separator as "#P#". The text case is fixed even if
|
||||
lower_case_table_names is set to 1 or 2. This is true
|
||||
|
|
@ -5021,14 +5094,10 @@ retry:
|
|||
|
||||
ib_table = dict_table_open_on_name(
|
||||
par_case_name, FALSE, TRUE,
|
||||
DICT_ERR_IGNORE_NONE);
|
||||
ignore_err);
|
||||
}
|
||||
|
||||
if (!ib_table) {
|
||||
++retries;
|
||||
os_thread_sleep(100000);
|
||||
goto retry;
|
||||
} else {
|
||||
if (ib_table) {
|
||||
#ifndef __WIN__
|
||||
sql_print_warning("Partition table %s opened "
|
||||
"after converting to lower "
|
||||
|
|
@ -5054,9 +5123,8 @@ retry:
|
|||
}
|
||||
|
||||
if (is_part) {
|
||||
sql_print_error("Failed to open table %s after "
|
||||
"%lu attempts.\n", norm_name,
|
||||
retries);
|
||||
sql_print_error("Failed to open table %s.\n",
|
||||
norm_name);
|
||||
}
|
||||
|
||||
ib_logf(IB_LOG_LEVEL_WARN,
|
||||
|
|
@ -5299,8 +5367,6 @@ ha_innobase::clone(
|
|||
mem_root));
|
||||
if (new_handler) {
|
||||
DBUG_ASSERT(new_handler->prebuilt != NULL);
|
||||
DBUG_ASSERT(new_handler->user_thd == user_thd);
|
||||
DBUG_ASSERT(new_handler->prebuilt->trx == prebuilt->trx);
|
||||
|
||||
new_handler->prebuilt->select_lock_type
|
||||
= prebuilt->select_lock_type;
|
||||
|
|
@ -5680,8 +5746,8 @@ ulint
|
|||
innobase_mysql_fts_get_token(
|
||||
/*=========================*/
|
||||
CHARSET_INFO* cs, /*!< in: Character set */
|
||||
byte* start, /*!< in: start of text */
|
||||
byte* end, /*!< in: one character past end of
|
||||
const byte* start, /*!< in: start of text */
|
||||
const byte* end, /*!< in: one character past end of
|
||||
text */
|
||||
fts_string_t* token, /*!< out: token's text */
|
||||
ulint* offset) /*!< out: offset to token,
|
||||
|
|
@ -5689,13 +5755,12 @@ innobase_mysql_fts_get_token(
|
|||
'start' */
|
||||
{
|
||||
int mbl;
|
||||
uchar* doc = start;
|
||||
const uchar* doc = start;
|
||||
|
||||
ut_a(cs);
|
||||
|
||||
token->f_n_char = token->f_len = 0;
|
||||
|
||||
do {
|
||||
for (;;) {
|
||||
|
||||
if (doc >= end) {
|
||||
|
|
@ -5705,7 +5770,7 @@ innobase_mysql_fts_get_token(
|
|||
int ctype;
|
||||
|
||||
mbl = cs->cset->ctype(
|
||||
cs, &ctype, (uchar*) doc, (uchar*) end);
|
||||
cs, &ctype, doc, (const uchar*) end);
|
||||
|
||||
if (true_word_char(ctype, *doc)) {
|
||||
break;
|
||||
|
|
@ -5717,7 +5782,7 @@ innobase_mysql_fts_get_token(
|
|||
ulint mwc = 0;
|
||||
ulint length = 0;
|
||||
|
||||
token->f_str = doc;
|
||||
token->f_str = const_cast<byte*>(doc);
|
||||
|
||||
while (doc < end) {
|
||||
|
||||
|
|
@ -5725,7 +5790,6 @@ innobase_mysql_fts_get_token(
|
|||
|
||||
mbl = cs->cset->ctype(
|
||||
cs, &ctype, (uchar*) doc, (uchar*) end);
|
||||
|
||||
if (true_word_char(ctype, *doc)) {
|
||||
mwc = 0;
|
||||
} else if (!misc_word_char(*doc) || mwc) {
|
||||
|
|
@ -5742,12 +5806,6 @@ innobase_mysql_fts_get_token(
|
|||
token->f_len = (uint) (doc - token->f_str) - mwc;
|
||||
token->f_n_char = length;
|
||||
|
||||
return(doc - start);
|
||||
|
||||
} while (doc < end);
|
||||
|
||||
token->f_str[token->f_len] = 0;
|
||||
|
||||
return(doc - start);
|
||||
}
|
||||
|
||||
|
|
@ -7476,6 +7534,12 @@ ha_innobase::unlock_row(void)
|
|||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/* Ideally, this assert must be in the beginning of the function.
|
||||
But there are some calls to this function from the SQL layer when the
|
||||
transaction is in state TRX_STATE_NOT_STARTED. The check on
|
||||
prebuilt->select_lock_type above gets around this issue. */
|
||||
ut_ad(trx_state_eq(prebuilt->trx, TRX_STATE_ACTIVE));
|
||||
|
||||
switch (prebuilt->row_read_type) {
|
||||
case ROW_READ_WITH_LOCKS:
|
||||
if (!srv_locks_unsafe_for_binlog
|
||||
|
|
@ -8310,7 +8374,7 @@ ha_innobase::ft_init_ext(
|
|||
{
|
||||
trx_t* trx;
|
||||
dict_table_t* table;
|
||||
ulint error;
|
||||
dberr_t error;
|
||||
byte* query = (byte*) key->ptr();
|
||||
ulint query_len = key->length();
|
||||
const CHARSET_INFO* char_set = key->charset();
|
||||
|
|
@ -8387,23 +8451,24 @@ ha_innobase::ft_init_ext(
|
|||
|
||||
error = fts_query(trx, index, flags, query, query_len, &result);
|
||||
|
||||
// FIXME: Proper error handling and diagnostic
|
||||
if (error != DB_SUCCESS) {
|
||||
fprintf(stderr, "Error processing query\n");
|
||||
} else {
|
||||
/* Allocate FTS handler, and instantiate it before return */
|
||||
fts_hdl = (NEW_FT_INFO*) my_malloc(sizeof(NEW_FT_INFO),
|
||||
my_error(convert_error_code_to_mysql(error, 0, NULL),
|
||||
MYF(0));
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
fts_hdl->please = (struct _ft_vft*)(&ft_vft_result);
|
||||
fts_hdl->could_you = (struct _ft_vft_ext*)(&ft_vft_ext_result);
|
||||
/* Allocate FTS handler, and instantiate it before return */
|
||||
fts_hdl = static_cast<NEW_FT_INFO*>(my_malloc(sizeof(NEW_FT_INFO),
|
||||
MYF(0)));
|
||||
|
||||
fts_hdl->please = const_cast<_ft_vft*>(&ft_vft_result);
|
||||
fts_hdl->could_you = const_cast<_ft_vft_ext*>(&ft_vft_ext_result);
|
||||
fts_hdl->ft_prebuilt = prebuilt;
|
||||
fts_hdl->ft_result = result;
|
||||
|
||||
/* FIXME: Re-evluate the condition when Bug 14469540
|
||||
is resolved */
|
||||
prebuilt->in_fts_query = true;
|
||||
}
|
||||
|
||||
return((FT_INFO*) fts_hdl);
|
||||
}
|
||||
|
|
@ -8922,6 +8987,9 @@ err_col:
|
|||
|
||||
mem_heap_free(heap);
|
||||
|
||||
DBUG_EXECUTE_IF("ib_create_err_tablespace_exist",
|
||||
err = DB_TABLESPACE_EXISTS;);
|
||||
|
||||
if (err == DB_DUPLICATE_KEY || err == DB_TABLESPACE_EXISTS) {
|
||||
char display_name[FN_REFLEN];
|
||||
char* buf_end = innobase_convert_identifier(
|
||||
|
|
@ -9515,6 +9583,11 @@ innobase_table_flags(
|
|||
DBUG_RETURN(false);
|
||||
}
|
||||
|
||||
if (key->flags & HA_USES_PARSER) {
|
||||
my_error(ER_INNODB_NO_FT_USES_PARSER, MYF(0));
|
||||
DBUG_RETURN(false);
|
||||
}
|
||||
|
||||
if (fts_doc_id_index_bad) {
|
||||
goto index_bad;
|
||||
}
|
||||
|
|
@ -9837,7 +9910,7 @@ ha_innobase::create(
|
|||
|
||||
/* Check whether there already exists FTS_DOC_ID_INDEX */
|
||||
ret = innobase_fts_check_doc_id_index_in_def(
|
||||
form->s->keys, form->s->key_info);
|
||||
form->s->keys, form->key_info);
|
||||
|
||||
switch (ret) {
|
||||
case FTS_INCORRECT_DOC_ID_INDEX:
|
||||
|
|
@ -9893,6 +9966,16 @@ ha_innobase::create(
|
|||
}
|
||||
}
|
||||
|
||||
/* Cache all the FTS indexes on this table in the FTS specific
|
||||
structure. They are used for FTS indexed column update handling. */
|
||||
if (flags2 & DICT_TF2_FTS) {
|
||||
fts_t* fts = innobase_table->fts;
|
||||
|
||||
ut_a(fts != NULL);
|
||||
|
||||
dict_table_get_all_fts_indexes(innobase_table, fts->indexes);
|
||||
}
|
||||
|
||||
stmt = innobase_get_stmt(thd, &stmt_len);
|
||||
|
||||
if (stmt) {
|
||||
|
|
@ -9931,15 +10014,6 @@ ha_innobase::create(
|
|||
goto cleanup;
|
||||
}
|
||||
}
|
||||
/* Cache all the FTS indexes on this table in the FTS specific
|
||||
structure. They are used for FTS indexed column update handling. */
|
||||
if (flags2 & DICT_TF2_FTS) {
|
||||
fts_t* fts = innobase_table->fts;
|
||||
|
||||
ut_a(fts != NULL);
|
||||
|
||||
dict_table_get_all_fts_indexes(innobase_table, fts->indexes);
|
||||
}
|
||||
|
||||
innobase_commit_low(trx);
|
||||
|
||||
|
|
@ -10407,8 +10481,10 @@ innobase_rename_table(
|
|||
|
||||
DEBUG_SYNC_C("innodb_rename_table_ready");
|
||||
|
||||
trx_start_if_not_started(trx);
|
||||
|
||||
/* Serialize data dictionary operations with dictionary mutex:
|
||||
no deadlocks can occur then in these operations */
|
||||
no deadlocks can occur then in these operations. */
|
||||
|
||||
row_mysql_lock_data_dictionary(trx);
|
||||
|
||||
|
|
@ -10446,6 +10522,7 @@ innobase_rename_table(
|
|||
normalize_table_name_low(
|
||||
par_case_name, from, FALSE);
|
||||
#endif
|
||||
trx_start_if_not_started(trx);
|
||||
error = row_rename_table_for_mysql(
|
||||
par_case_name, norm_to, trx, TRUE);
|
||||
}
|
||||
|
|
@ -11054,8 +11131,6 @@ ha_innobase::info_low(
|
|||
|
||||
if (dict_stats_is_persistent_enabled(ib_table)) {
|
||||
|
||||
ut_ad(!srv_read_only_mode);
|
||||
|
||||
if (is_analyze) {
|
||||
opt = DICT_STATS_RECALC_PERSISTENT;
|
||||
} else {
|
||||
|
|
@ -11602,14 +11677,15 @@ ha_innobase::check(
|
|||
index_name, sizeof index_name,
|
||||
index->name, TRUE);
|
||||
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
push_warning_printf(
|
||||
thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_NOT_KEYFILE,
|
||||
"InnoDB: The B-tree of"
|
||||
" index %s is corrupted.",
|
||||
index_name);
|
||||
is_ok = FALSE;
|
||||
dict_set_corrupted(
|
||||
index, prebuilt->trx, "CHECK TABLE");
|
||||
index, prebuilt->trx, "CHECK TABLE-check index");
|
||||
}
|
||||
|
||||
if (thd_kill_level(user_thd)) {
|
||||
|
|
@ -11625,15 +11701,18 @@ ha_innobase::check(
|
|||
n_rows_in_table = n_rows;
|
||||
} else if (!(index->type & DICT_FTS)
|
||||
&& (n_rows != n_rows_in_table)) {
|
||||
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
push_warning_printf(
|
||||
thd, Sql_condition::WARN_LEVEL_WARN,
|
||||
ER_NOT_KEYFILE,
|
||||
"InnoDB: Index '%-.200s'"
|
||||
" contains %lu entries,"
|
||||
" should be %lu.",
|
||||
"InnoDB: Index '%-.200s' contains %lu"
|
||||
" entries, should be %lu.",
|
||||
index->name,
|
||||
(ulong) n_rows,
|
||||
(ulong) n_rows_in_table);
|
||||
is_ok = FALSE;
|
||||
dict_set_corrupted(
|
||||
index, prebuilt->trx,
|
||||
"CHECK TABLE; Wrong count");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -12301,11 +12380,10 @@ ha_innobase::external_lock(
|
|||
&& !(table_flags() & HA_BINLOG_STMT_CAPABLE)
|
||||
&& thd_binlog_format(thd) == BINLOG_FORMAT_STMT
|
||||
&& thd_binlog_filter_ok(thd)
|
||||
&& thd_sqlcom_can_generate_row_events(thd))
|
||||
{
|
||||
int skip = 0;
|
||||
&& thd_sqlcom_can_generate_row_events(thd)) {
|
||||
bool skip = 0;
|
||||
/* used by test case */
|
||||
DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = 1;);
|
||||
DBUG_EXECUTE_IF("no_innodb_binlog_errors", skip = true;);
|
||||
if (!skip) {
|
||||
my_error(ER_BINLOG_STMT_MODE_AND_ROW_ENGINE, MYF(0),
|
||||
" InnoDB is limited to row-logging when "
|
||||
|
|
@ -12323,14 +12401,23 @@ ha_innobase::external_lock(
|
|||
|| thd_sql_command(thd) == SQLCOM_DROP_TABLE
|
||||
|| thd_sql_command(thd) == SQLCOM_ALTER_TABLE
|
||||
|| thd_sql_command(thd) == SQLCOM_OPTIMIZE
|
||||
|| thd_sql_command(thd) == SQLCOM_CREATE_TABLE
|
||||
|| (thd_sql_command(thd) == SQLCOM_CREATE_TABLE
|
||||
&& lock_type == F_WRLCK)
|
||||
|| thd_sql_command(thd) == SQLCOM_CREATE_INDEX
|
||||
|| thd_sql_command(thd) == SQLCOM_DROP_INDEX
|
||||
|| thd_sql_command(thd) == SQLCOM_DELETE)) {
|
||||
|
||||
ib_senderrf(thd, IB_LOG_LEVEL_WARN, ER_READ_ONLY_MODE);
|
||||
|
||||
if (thd_sql_command(thd) == SQLCOM_CREATE_TABLE)
|
||||
{
|
||||
ib_senderrf(thd, IB_LOG_LEVEL_WARN,
|
||||
ER_READ_ONLY_MODE);
|
||||
DBUG_RETURN(HA_ERR_TABLE_READONLY);
|
||||
} else {
|
||||
ib_senderrf(thd, IB_LOG_LEVEL_WARN,
|
||||
ER_READ_ONLY_MODE);
|
||||
DBUG_RETURN(HA_ERR_TABLE_READONLY);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
trx = prebuilt->trx;
|
||||
|
|
@ -13051,7 +13138,9 @@ ha_innobase::store_lock(
|
|||
|| sql_command == SQLCOM_DROP_TABLE
|
||||
|| sql_command == SQLCOM_ALTER_TABLE
|
||||
|| sql_command == SQLCOM_OPTIMIZE
|
||||
|| sql_command == SQLCOM_CREATE_TABLE
|
||||
|| (sql_command == SQLCOM_CREATE_TABLE
|
||||
&& (lock_type >= TL_WRITE_CONCURRENT_INSERT
|
||||
&& lock_type <= TL_WRITE))
|
||||
|| sql_command == SQLCOM_CREATE_INDEX
|
||||
|| sql_command == SQLCOM_DROP_INDEX
|
||||
|| sql_command == SQLCOM_DELETE)) {
|
||||
|
|
@ -15165,6 +15254,80 @@ innodb_srv_buf_dump_filename_validate(
|
|||
# define innodb_srv_buf_dump_filename_validate NULL
|
||||
#endif /* __WIN__ */
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
static char* srv_buffer_pool_evict;
|
||||
|
||||
/****************************************************************//**
|
||||
Evict all uncompressed pages of compressed tables from the buffer pool.
|
||||
Keep the compressed pages in the buffer pool.
|
||||
@return whether all uncompressed pages were evicted */
|
||||
static __attribute__((warn_unused_result))
|
||||
bool
|
||||
innodb_buffer_pool_evict_uncompressed(void)
|
||||
/*=======================================*/
|
||||
{
|
||||
bool all_evicted = true;
|
||||
|
||||
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
|
||||
buf_pool_t* buf_pool = &buf_pool_ptr[i];
|
||||
|
||||
buf_pool_mutex_enter(buf_pool);
|
||||
|
||||
for (buf_block_t* block = UT_LIST_GET_LAST(
|
||||
buf_pool->unzip_LRU);
|
||||
block != NULL; ) {
|
||||
buf_block_t* prev_block = UT_LIST_GET_PREV(
|
||||
unzip_LRU, block);
|
||||
ut_ad(buf_block_get_state(block)
|
||||
== BUF_BLOCK_FILE_PAGE);
|
||||
ut_ad(block->in_unzip_LRU_list);
|
||||
ut_ad(block->page.in_LRU_list);
|
||||
|
||||
if (!buf_LRU_free_page(&block->page, false)) {
|
||||
all_evicted = false;
|
||||
}
|
||||
|
||||
block = prev_block;
|
||||
}
|
||||
|
||||
buf_pool_mutex_exit(buf_pool);
|
||||
}
|
||||
|
||||
return(all_evicted);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Called on SET GLOBAL innodb_buffer_pool_evict=...
|
||||
Handles some values specially, to evict pages from the buffer pool.
|
||||
SET GLOBAL innodb_buffer_pool_evict='uncompressed'
|
||||
evicts all uncompressed page frames of compressed tablespaces. */
|
||||
static
|
||||
void
|
||||
innodb_buffer_pool_evict_update(
|
||||
/*============================*/
|
||||
THD* thd, /*!< in: thread handle */
|
||||
struct st_mysql_sys_var*var, /*!< in: pointer to system variable */
|
||||
void* var_ptr,/*!< out: ignored */
|
||||
const void* save) /*!< in: immediate result
|
||||
from check function */
|
||||
{
|
||||
if (const char* op = *static_cast<const char*const*>(save)) {
|
||||
if (!strcmp(op, "uncompressed")) {
|
||||
for (uint tries = 0; tries < 10000; tries++) {
|
||||
if (innodb_buffer_pool_evict_uncompressed()) {
|
||||
return;
|
||||
}
|
||||
|
||||
os_thread_sleep(10000);
|
||||
}
|
||||
|
||||
/* We failed to evict all uncompressed pages. */
|
||||
ut_ad(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/****************************************************************//**
|
||||
Update the system variable innodb_monitor_enable and enable
|
||||
specified monitor counter.
|
||||
|
|
@ -15241,29 +15404,6 @@ innodb_reset_all_monitor_update(
|
|||
TRUE);
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Update the system variable innodb_compression_level using the "saved"
|
||||
value. This function is registered as a callback with MySQL. */
|
||||
static
|
||||
void
|
||||
innodb_compression_level_update(
|
||||
/*============================*/
|
||||
THD* thd, /*!< in: thread handle */
|
||||
struct st_mysql_sys_var* var, /*!< in: pointer to
|
||||
system variable */
|
||||
void* var_ptr,/*!< out: where the
|
||||
formal string goes */
|
||||
const void* save) /*!< in: immediate result
|
||||
from check function */
|
||||
{
|
||||
/* We have this call back just to avoid confusion between
|
||||
ulong and ulint datatypes. */
|
||||
innobase_compression_level =
|
||||
(*static_cast<const ulong*>(save));
|
||||
page_compression_level =
|
||||
(static_cast<const ulint>(innobase_compression_level));
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Parse and enable InnoDB monitor counters during server startup.
|
||||
User can list the monitor counters/groups to be enable by specifying
|
||||
|
|
@ -15441,6 +15581,7 @@ innobase_fts_find_ranking(
|
|||
#ifdef UNIV_DEBUG
|
||||
static my_bool innodb_purge_run_now = TRUE;
|
||||
static my_bool innodb_purge_stop_now = TRUE;
|
||||
static my_bool innodb_log_checkpoint_now = TRUE;
|
||||
|
||||
/****************************************************************//**
|
||||
Set the purge state to RUN. If purge is disabled then it
|
||||
|
|
@ -15487,6 +15628,33 @@ purge_stop_now_set(
|
|||
trx_purge_stop();
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
Force innodb to checkpoint. */
|
||||
static
|
||||
void
|
||||
checkpoint_now_set(
|
||||
/*===============*/
|
||||
THD* thd /*!< in: thread handle */
|
||||
__attribute__((unused)),
|
||||
struct st_mysql_sys_var* var /*!< in: pointer to system
|
||||
variable */
|
||||
__attribute__((unused)),
|
||||
void* var_ptr /*!< out: where the formal
|
||||
string goes */
|
||||
__attribute__((unused)),
|
||||
const void* save) /*!< in: immediate result from
|
||||
check function */
|
||||
{
|
||||
if (*(my_bool*) save) {
|
||||
while (log_sys->last_checkpoint_lsn < log_sys->lsn) {
|
||||
log_make_checkpoint_at(LSN_MAX, TRUE);
|
||||
fil_flush_file_spaces(FIL_LOG);
|
||||
}
|
||||
fil_write_flushed_lsn_to_data_files(log_sys->lsn, 0);
|
||||
fil_flush_file_spaces(FIL_TABLESPACE);
|
||||
}
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/***********************************************************************
|
||||
|
|
@ -15725,6 +15893,11 @@ static MYSQL_SYSVAR_BOOL(purge_stop_now, innodb_purge_stop_now,
|
|||
PLUGIN_VAR_OPCMDARG,
|
||||
"Set purge state to STOP",
|
||||
NULL, purge_stop_now_set, FALSE);
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(log_checkpoint_now, innodb_log_checkpoint_now,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
"Force checkpoint now",
|
||||
NULL, checkpoint_now_set, FALSE);
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(purge_batch_size, srv_purge_batch_size,
|
||||
|
|
@ -15744,7 +15917,7 @@ static MYSQL_SYSVAR_ULONG(purge_threads, srv_n_purge_threads,
|
|||
32, 0); /* Maximum value */
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(sync_array_size, srv_sync_array_size,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
|
||||
"Size of the mutex/lock wait array.",
|
||||
NULL, NULL,
|
||||
1, /* Default setting */
|
||||
|
|
@ -15952,12 +16125,20 @@ static MYSQL_SYSVAR_ULONG(replication_delay, srv_replication_delay,
|
|||
"innodb_thread_concurrency is reached (0 by default)",
|
||||
NULL, NULL, 0, 0, ~0UL, 0);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(compression_level, innobase_compression_level,
|
||||
static MYSQL_SYSVAR_UINT(compression_level, page_zip_level,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"Compression level used for compressed row format. 0 is no compression"
|
||||
", 1 is fastest, 9 is best compression and default is 6.",
|
||||
NULL, innodb_compression_level_update,
|
||||
DEFAULT_COMPRESSION_LEVEL, 0, 9, 0);
|
||||
NULL, NULL, DEFAULT_COMPRESSION_LEVEL, 0, 9, 0);
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(log_compressed_pages, page_zip_log_pages,
|
||||
PLUGIN_VAR_OPCMDARG,
|
||||
"Enables/disables the logging of entire compressed page images."
|
||||
" InnoDB logs the compressed pages to prevent corruption if"
|
||||
" the zlib compression algorithm changes."
|
||||
" When turned OFF, InnoDB will assume that the zlib"
|
||||
" compression algorithm doesn't change.",
|
||||
NULL, NULL, TRUE);
|
||||
|
||||
static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
|
||||
|
|
@ -16009,6 +16190,13 @@ static MYSQL_SYSVAR_BOOL(buffer_pool_dump_at_shutdown, srv_buffer_pool_dump_at_s
|
|||
"Dump the buffer pool into a file named @@innodb_buffer_pool_filename",
|
||||
NULL, NULL, FALSE);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
static MYSQL_SYSVAR_STR(buffer_pool_evict, srv_buffer_pool_evict,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"Evict pages from the buffer pool",
|
||||
NULL, innodb_buffer_pool_evict_update, "");
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
static MYSQL_SYSVAR_BOOL(buffer_pool_load_now, innodb_buffer_pool_load_now,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"Trigger an immediate load of the buffer pool from a file named @@innodb_buffer_pool_filename",
|
||||
|
|
@ -16074,6 +16262,16 @@ static MYSQL_SYSVAR_ULONG(ft_cache_size, fts_max_cache_size,
|
|||
"InnoDB Fulltext search cache size in bytes",
|
||||
NULL, NULL, 8000000, 1600000, 80000000, 0);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(ft_total_cache_size, fts_max_total_cache_size,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
|
||||
"Total memory allocated for InnoDB Fulltext Search cache",
|
||||
NULL, NULL, 640000000, 32000000, 1600000000, 0);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(ft_result_cache_limit, fts_result_cache_limit,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
"InnoDB Fulltext search query result cache limit in bytes",
|
||||
NULL, NULL, 2000000000L, 1000000L, ~0UL, 0);
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(ft_min_token_size, fts_min_token_size,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
|
||||
"InnoDB Fulltext search minimum token size in characters",
|
||||
|
|
@ -16082,7 +16280,7 @@ static MYSQL_SYSVAR_ULONG(ft_min_token_size, fts_min_token_size,
|
|||
static MYSQL_SYSVAR_ULONG(ft_max_token_size, fts_max_token_size,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
|
||||
"InnoDB Fulltext search maximum token size in characters",
|
||||
NULL, NULL, HA_FT_MAXCHARLEN, 10, FTS_MAX_WORD_LEN , 0);
|
||||
NULL, NULL, FTS_MAX_WORD_LEN_IN_CHAR, 10, FTS_MAX_WORD_LEN_IN_CHAR, 0);
|
||||
|
||||
|
||||
static MYSQL_SYSVAR_ULONG(ft_num_word_optimize, fts_num_word_optimize,
|
||||
|
|
@ -16153,10 +16351,12 @@ static MYSQL_SYSVAR_ULONG(log_files_in_group, srv_n_log_files,
|
|||
"Number of log files in the log group. InnoDB writes to the files in a circular fashion.",
|
||||
NULL, NULL, 2, 2, SRV_N_LOG_FILES_MAX, 0);
|
||||
|
||||
/* Note that the default and minimum values are set to 0 to
|
||||
detect if the option is passed and print deprecation message */
|
||||
static MYSQL_SYSVAR_LONG(mirrored_log_groups, innobase_mirrored_log_groups,
|
||||
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
|
||||
"Number of identical copies of log groups we keep for the database. Currently this should be set to 1.",
|
||||
NULL, NULL, 1, 1, 10, 0);
|
||||
NULL, NULL, 0, 0, 10, 0);
|
||||
|
||||
static MYSQL_SYSVAR_UINT(old_blocks_pct, innobase_old_blocks_pct,
|
||||
PLUGIN_VAR_RQCMDARG,
|
||||
|
|
@ -16432,6 +16632,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
|
|||
MYSQL_SYSVAR(buffer_pool_filename),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_now),
|
||||
MYSQL_SYSVAR(buffer_pool_dump_at_shutdown),
|
||||
#ifdef UNIV_DEBUG
|
||||
MYSQL_SYSVAR(buffer_pool_evict),
|
||||
#endif /* UNIV_DEBUG */
|
||||
MYSQL_SYSVAR(buffer_pool_load_now),
|
||||
MYSQL_SYSVAR(buffer_pool_load_abort),
|
||||
MYSQL_SYSVAR(buffer_pool_load_at_startup),
|
||||
|
|
@ -16466,6 +16669,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
|
|||
MYSQL_SYSVAR(force_recovery_crash),
|
||||
#endif /* !DBUG_OFF */
|
||||
MYSQL_SYSVAR(ft_cache_size),
|
||||
MYSQL_SYSVAR(ft_total_cache_size),
|
||||
MYSQL_SYSVAR(ft_result_cache_limit),
|
||||
MYSQL_SYSVAR(ft_enable_stopword),
|
||||
MYSQL_SYSVAR(ft_max_token_size),
|
||||
MYSQL_SYSVAR(ft_min_token_size),
|
||||
|
|
@ -16484,6 +16689,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
|
|||
MYSQL_SYSVAR(log_file_size),
|
||||
MYSQL_SYSVAR(log_files_in_group),
|
||||
MYSQL_SYSVAR(log_group_home_dir),
|
||||
MYSQL_SYSVAR(log_compressed_pages),
|
||||
MYSQL_SYSVAR(max_dirty_pages_pct),
|
||||
MYSQL_SYSVAR(max_dirty_pages_pct_lwm),
|
||||
MYSQL_SYSVAR(adaptive_flushing_lwm),
|
||||
|
|
@ -16548,6 +16754,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
|
|||
#ifdef UNIV_DEBUG
|
||||
MYSQL_SYSVAR(purge_run_now),
|
||||
MYSQL_SYSVAR(purge_stop_now),
|
||||
MYSQL_SYSVAR(log_checkpoint_now),
|
||||
#endif /* UNIV_DEBUG */
|
||||
#if defined UNIV_DEBUG || defined UNIV_PERF_DEBUG
|
||||
MYSQL_SYSVAR(page_hash_locks),
|
||||
|
|
@ -16600,7 +16807,6 @@ i_s_innodb_buffer_page_lru,
|
|||
i_s_innodb_buffer_stats,
|
||||
i_s_innodb_metrics,
|
||||
i_s_innodb_ft_default_stopword,
|
||||
i_s_innodb_ft_inserted,
|
||||
i_s_innodb_ft_deleted,
|
||||
i_s_innodb_ft_being_deleted,
|
||||
i_s_innodb_ft_config,
|
||||
|
|
@ -17056,6 +17262,23 @@ ib_logf(
|
|||
}
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Converts an identifier from my_charset_filename to UTF-8 charset.
|
||||
@return result string length, as returned by strconvert() */
|
||||
uint
|
||||
innobase_convert_to_filename_charset(
|
||||
/*=================================*/
|
||||
char* to, /* out: converted identifier */
|
||||
const char* from, /* in: identifier to convert */
|
||||
ulint len) /* in: length of 'to', in bytes */
|
||||
{
|
||||
uint errors;
|
||||
CHARSET_INFO* cs_to = &my_charset_filename;
|
||||
CHARSET_INFO* cs_from = system_charset_info;
|
||||
|
||||
return(strconvert(cs_from, from, strlen(from), cs_to, to, len, &errors));
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
Converts an identifier from my_charset_filename to UTF-8 charset.
|
||||
@return result string length, as returned by strconvert() */
|
||||
|
|
|
|||
|
|
@ -634,7 +634,7 @@ void
|
|||
innobase_copy_frm_flags_from_create_info(
|
||||
/*=====================================*/
|
||||
dict_table_t* innodb_table, /*!< in/out: InnoDB table */
|
||||
HA_CREATE_INFO* create_info); /*!< in: create info */
|
||||
const HA_CREATE_INFO* create_info); /*!< in: create info */
|
||||
|
||||
/*********************************************************************//**
|
||||
Copy table flags from MySQL's TABLE_SHARE into an InnoDB table object.
|
||||
|
|
@ -646,4 +646,4 @@ void
|
|||
innobase_copy_frm_flags_from_table_share(
|
||||
/*=====================================*/
|
||||
dict_table_t* innodb_table, /*!< in/out: InnoDB table */
|
||||
TABLE_SHARE* table_share); /*!< in: table share */
|
||||
const TABLE_SHARE* table_share); /*!< in: table share */
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2007, 2013, 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
|
||||
|
|
@ -24,7 +24,7 @@ Created July 18, 2007 Vasil Dimov
|
|||
*******************************************************/
|
||||
|
||||
#include <mysqld_error.h>
|
||||
#include <sql_acl.h> // PROCESS_ACL
|
||||
#include <sql_acl.h>
|
||||
|
||||
#include <m_ctype.h>
|
||||
#include <hash.h>
|
||||
|
|
@ -35,18 +35,19 @@ Created July 18, 2007 Vasil Dimov
|
|||
#include <sql_plugin.h>
|
||||
#include <innodb_priv.h>
|
||||
|
||||
#include "btr0pcur.h" /* for file sys_tables related info. */
|
||||
#include "btr0pcur.h"
|
||||
#include "btr0types.h"
|
||||
#include "buf0buddy.h" /* for i_s_cmpmem */
|
||||
#include "buf0buf.h" /* for buf_pool */
|
||||
#include "dict0dict.h" /* for dict_table_stats_lock() */
|
||||
#include "dict0load.h" /* for file sys_tables related info. */
|
||||
#include "dict0dict.h"
|
||||
#include "dict0load.h"
|
||||
#include "buf0buddy.h"
|
||||
#include "buf0buf.h"
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "dict0mem.h"
|
||||
#include "dict0types.h"
|
||||
#include "ha_prototypes.h" /* for innobase_convert_name() */
|
||||
#include "srv0start.h" /* for srv_was_started */
|
||||
#include "ha_prototypes.h"
|
||||
#include "srv0start.h"
|
||||
#include "trx0i_s.h"
|
||||
#include "trx0trx.h" /* for TRX_QUE_STATE_STR_MAX_LEN */
|
||||
#include "trx0trx.h"
|
||||
#include "srv0mon.h"
|
||||
#include "fut0fut.h"
|
||||
#include "pars0pars.h"
|
||||
|
|
@ -64,8 +65,12 @@ struct buf_page_desc_t{
|
|||
ulint type_value; /*!< Page type or page state */
|
||||
};
|
||||
|
||||
/** Any states greater than FIL_PAGE_TYPE_LAST would be treated as unknown. */
|
||||
#define I_S_PAGE_TYPE_UNKNOWN (FIL_PAGE_TYPE_LAST + 1)
|
||||
/** Change buffer B-tree page */
|
||||
#define I_S_PAGE_TYPE_IBUF (FIL_PAGE_TYPE_LAST + 1)
|
||||
|
||||
/** Any states greater than I_S_PAGE_TYPE_IBUF would be treated as
|
||||
unknown. */
|
||||
#define I_S_PAGE_TYPE_UNKNOWN (I_S_PAGE_TYPE_IBUF + 1)
|
||||
|
||||
/** We also define I_S_PAGE_TYPE_INDEX as the Index Page's position
|
||||
in i_s_page_type[] array */
|
||||
|
|
@ -86,6 +91,7 @@ static buf_page_desc_t i_s_page_type[] = {
|
|||
{"BLOB", FIL_PAGE_TYPE_BLOB},
|
||||
{"COMPRESSED_BLOB", FIL_PAGE_TYPE_ZBLOB},
|
||||
{"COMPRESSED_BLOB2", FIL_PAGE_TYPE_ZBLOB2},
|
||||
{"IBUF_INDEX", I_S_PAGE_TYPE_IBUF},
|
||||
{"UNKNOWN", I_S_PAGE_TYPE_UNKNOWN}
|
||||
};
|
||||
|
||||
|
|
@ -2900,8 +2906,7 @@ UNIV_INTERN struct st_maria_plugin i_s_innodb_ft_default_stopword =
|
|||
};
|
||||
|
||||
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_DELETED
|
||||
INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED and
|
||||
INFORMATION_SCHEMA.INNODB_FT_INSERTED */
|
||||
INFORMATION_SCHEMA.INNODB_FT_BEING_DELETED */
|
||||
static ST_FIELD_INFO i_s_fts_doc_fields_info[] =
|
||||
{
|
||||
#define I_S_FTS_DOC_ID 0
|
||||
|
|
@ -3151,139 +3156,6 @@ UNIV_INTERN struct st_maria_plugin i_s_innodb_ft_being_deleted =
|
|||
STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
|
||||
};
|
||||
|
||||
/*******************************************************************//**
|
||||
Fill the dynamic table INFORMATION_SCHEMA.INNODB_FT_INSERTED.
|
||||
@return 0 on success, 1 on failure */
|
||||
static
|
||||
int
|
||||
i_s_fts_inserted_fill(
|
||||
/*==================*/
|
||||
THD* thd, /*!< in: thread */
|
||||
TABLE_LIST* tables, /*!< in/out: tables to fill */
|
||||
Item* ) /*!< in: condition (ignored) */
|
||||
{
|
||||
Field** fields;
|
||||
TABLE* table = (TABLE*) tables->table;
|
||||
trx_t* trx;
|
||||
fts_table_t fts_table;
|
||||
fts_doc_ids_t* inserted;
|
||||
dict_table_t* user_table;
|
||||
|
||||
DBUG_ENTER("i_s_fts_inserted_fill");
|
||||
|
||||
/* deny access to non-superusers */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (!fts_internal_tbl_name) {
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
user_table = dict_table_open_on_name(
|
||||
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
|
||||
|
||||
if (!user_table) {
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
inserted = fts_doc_ids_create();
|
||||
|
||||
trx = trx_allocate_for_background();
|
||||
trx->op_info = "Select for FTS ADDED Table";
|
||||
|
||||
FTS_INIT_FTS_TABLE(&fts_table, "ADDED", FTS_COMMON_TABLE, user_table);
|
||||
|
||||
fts_table_fetch_doc_ids(trx, &fts_table, inserted);
|
||||
|
||||
fields = table->field;
|
||||
|
||||
for (ulint j = 0; j < ib_vector_size(inserted->doc_ids); ++j) {
|
||||
doc_id_t doc_id;
|
||||
|
||||
doc_id = *(doc_id_t*) ib_vector_get_const(inserted->doc_ids, j);
|
||||
|
||||
OK(fields[I_S_FTS_DOC_ID]->store((longlong) doc_id, true));
|
||||
|
||||
OK(schema_table_store_record(thd, table));
|
||||
}
|
||||
|
||||
trx_free_for_background(trx);
|
||||
|
||||
fts_doc_ids_free(inserted);
|
||||
|
||||
dict_table_close(user_table, FALSE, FALSE);
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
/*******************************************************************//**
|
||||
Bind the dynamic table INFORMATION_SCHEMA.INNODB_FT_INSERTED
|
||||
@return 0 on success */
|
||||
static
|
||||
int
|
||||
i_s_fts_inserted_init(
|
||||
/*==================*/
|
||||
void* p) /*!< in/out: table schema object */
|
||||
{
|
||||
DBUG_ENTER("i_s_fts_inserted_init");
|
||||
ST_SCHEMA_TABLE* schema = (ST_SCHEMA_TABLE*) p;
|
||||
|
||||
schema->fields_info = i_s_fts_doc_fields_info;
|
||||
schema->fill_table = i_s_fts_inserted_fill;
|
||||
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
UNIV_INTERN struct st_maria_plugin i_s_innodb_ft_inserted =
|
||||
{
|
||||
/* the plugin type (a MYSQL_XXX_PLUGIN value) */
|
||||
/* int */
|
||||
STRUCT_FLD(type, MYSQL_INFORMATION_SCHEMA_PLUGIN),
|
||||
|
||||
/* pointer to type-specific plugin descriptor */
|
||||
/* void* */
|
||||
STRUCT_FLD(info, &i_s_info),
|
||||
|
||||
/* plugin name */
|
||||
/* const char* */
|
||||
STRUCT_FLD(name, "INNODB_FT_INSERTED"),
|
||||
|
||||
/* plugin author (for SHOW PLUGINS) */
|
||||
/* const char* */
|
||||
STRUCT_FLD(author, plugin_author),
|
||||
|
||||
/* general descriptive text (for SHOW PLUGINS) */
|
||||
/* const char* */
|
||||
STRUCT_FLD(descr, "INNODB AUXILIARY FTS INSERTED TABLE"),
|
||||
|
||||
/* the plugin license (PLUGIN_LICENSE_XXX) */
|
||||
/* int */
|
||||
STRUCT_FLD(license, PLUGIN_LICENSE_GPL),
|
||||
|
||||
/* the function to invoke when plugin is loaded */
|
||||
/* int (*)(void*); */
|
||||
STRUCT_FLD(init, i_s_fts_inserted_init),
|
||||
|
||||
/* the function to invoke when plugin is unloaded */
|
||||
/* int (*)(void*); */
|
||||
STRUCT_FLD(deinit, i_s_common_deinit),
|
||||
|
||||
/* plugin version (for SHOW PLUGINS) */
|
||||
/* unsigned int */
|
||||
STRUCT_FLD(version, INNODB_VERSION_SHORT),
|
||||
|
||||
/* struct st_mysql_show_var* */
|
||||
STRUCT_FLD(status_vars, NULL),
|
||||
|
||||
/* struct st_mysql_sys_var** */
|
||||
STRUCT_FLD(system_vars, NULL),
|
||||
|
||||
/* Maria extension */
|
||||
STRUCT_FLD(version_info, INNODB_VERSION_STR),
|
||||
STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_STABLE),
|
||||
};
|
||||
|
||||
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_FT_INDEX_CACHED and
|
||||
INFORMATION_SCHEMA.INNODB_FT_INDEX_TABLE */
|
||||
static ST_FIELD_INFO i_s_fts_index_fields_info[] =
|
||||
|
|
@ -3875,14 +3747,8 @@ static ST_FIELD_INFO i_s_fts_config_fields_info[] =
|
|||
static const char* fts_config_key[] = {
|
||||
FTS_OPTIMIZE_LIMIT_IN_SECS,
|
||||
FTS_SYNCED_DOC_ID,
|
||||
FTS_LAST_OPTIMIZED_WORD,
|
||||
FTS_TOTAL_DELETED_COUNT,
|
||||
FTS_TOTAL_WORD_COUNT,
|
||||
FTS_OPTIMIZE_START_TIME,
|
||||
FTS_OPTIMIZE_END_TIME,
|
||||
FTS_STOPWORD_TABLE_NAME,
|
||||
FTS_USE_STOPWORD,
|
||||
FTS_TABLE_STATE,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
@ -4466,6 +4332,7 @@ i_s_innodb_buffer_stats_fill_table(
|
|||
buf_pool_info_t* pool_info;
|
||||
|
||||
DBUG_ENTER("i_s_innodb_buffer_fill_general");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* Only allow the PROCESS privilege holder to access the stats */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -4879,7 +4746,7 @@ i_s_innodb_buffer_page_fill(
|
|||
/* First three states are for compression pages and
|
||||
are not states we would get as we scan pages through
|
||||
buffer blocks */
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
state_str = NULL;
|
||||
|
|
@ -4951,14 +4818,21 @@ i_s_innodb_set_page_type(
|
|||
if (page_type == FIL_PAGE_INDEX) {
|
||||
const page_t* page = (const page_t*) frame;
|
||||
|
||||
page_info->index_id = btr_page_get_index_id(page);
|
||||
|
||||
/* FIL_PAGE_INDEX is a bit special, its value
|
||||
is defined as 17855, so we cannot use FIL_PAGE_INDEX
|
||||
to index into i_s_page_type[] array, its array index
|
||||
in the i_s_page_type[] array is I_S_PAGE_TYPE_INDEX
|
||||
(1) */
|
||||
(1) for index pages or I_S_PAGE_TYPE_IBUF for
|
||||
change buffer index pages */
|
||||
if (page_info->index_id
|
||||
== static_cast<index_id_t>(DICT_IBUF_ID_MIN
|
||||
+ IBUF_SPACE_ID)) {
|
||||
page_info->page_type = I_S_PAGE_TYPE_IBUF;
|
||||
} else {
|
||||
page_info->page_type = I_S_PAGE_TYPE_INDEX;
|
||||
|
||||
page_info->index_id = btr_page_get_index_id(page);
|
||||
}
|
||||
|
||||
page_info->data_size = (ulint)(page_header_get_field(
|
||||
page, PAGE_HEAP_TOP) - (page_is_comp(page)
|
||||
|
|
@ -4967,7 +4841,7 @@ i_s_innodb_set_page_type(
|
|||
- page_header_get_field(page, PAGE_GARBAGE));
|
||||
|
||||
page_info->num_recs = page_get_n_recs(page);
|
||||
} else if (page_type >= I_S_PAGE_TYPE_UNKNOWN) {
|
||||
} else if (page_type > FIL_PAGE_TYPE_LAST) {
|
||||
/* Encountered an unknown page type */
|
||||
page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
|
||||
} else {
|
||||
|
|
@ -5039,6 +4913,16 @@ i_s_innodb_buffer_page_get_info(
|
|||
|
||||
page_info->freed_page_clock = bpage->freed_page_clock;
|
||||
|
||||
switch (buf_page_get_io_fix(bpage)) {
|
||||
case BUF_IO_NONE:
|
||||
case BUF_IO_WRITE:
|
||||
case BUF_IO_PIN:
|
||||
break;
|
||||
case BUF_IO_READ:
|
||||
page_info->page_type = I_S_PAGE_TYPE_UNKNOWN;
|
||||
return;
|
||||
}
|
||||
|
||||
if (page_info->page_state == BUF_BLOCK_FILE_PAGE) {
|
||||
const buf_block_t*block;
|
||||
|
||||
|
|
@ -5075,6 +4959,7 @@ i_s_innodb_fill_buffer_pool(
|
|||
mem_heap_t* heap;
|
||||
|
||||
DBUG_ENTER("i_s_innodb_fill_buffer_pool");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
heap = mem_heap_create(10000);
|
||||
|
||||
|
|
@ -5574,7 +5459,7 @@ i_s_innodb_buf_page_lru_fill(
|
|||
state_str = "NO";
|
||||
break;
|
||||
/* We should not see following states */
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
|
|
@ -5640,6 +5525,7 @@ i_s_innodb_fill_buffer_lru(
|
|||
ulint lru_len;
|
||||
|
||||
DBUG_ENTER("i_s_innodb_fill_buffer_lru");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* Obtain buf_pool mutex before allocate info_buffer, since
|
||||
UT_LIST_GET_LEN(buf_pool->LRU) could change */
|
||||
|
|
@ -5966,6 +5852,7 @@ i_s_sys_tables_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_tables_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -6262,6 +6149,7 @@ i_s_sys_tables_fill_table_stats(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_tables_fill_table_stats");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -6511,6 +6399,7 @@ i_s_sys_indexes_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_indexes_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -6748,6 +6637,7 @@ i_s_sys_columns_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_columns_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -6951,6 +6841,7 @@ i_s_sys_fields_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_fields_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -7182,6 +7073,7 @@ i_s_sys_foreign_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_foreign_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -7396,6 +7288,7 @@ i_s_sys_foreign_cols_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_foreign_cols_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -7660,6 +7553,7 @@ i_s_sys_tablespaces_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_tablespaces_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
@ -7850,6 +7744,7 @@ i_s_sys_datafiles_fill_table(
|
|||
mtr_t mtr;
|
||||
|
||||
DBUG_ENTER("i_s_sys_datafiles_fill_table");
|
||||
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
|
||||
|
||||
/* deny access to user without PROCESS_ACL privilege */
|
||||
if (check_global_access(thd, PROCESS_ACL)) {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2007, 2013, 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
|
||||
|
|
@ -39,7 +39,6 @@ extern struct st_maria_plugin i_s_innodb_cmpmem;
|
|||
extern struct st_maria_plugin i_s_innodb_cmpmem_reset;
|
||||
extern struct st_maria_plugin i_s_innodb_metrics;
|
||||
extern struct st_maria_plugin i_s_innodb_ft_default_stopword;
|
||||
extern struct st_maria_plugin i_s_innodb_ft_inserted;
|
||||
extern struct st_maria_plugin i_s_innodb_ft_deleted;
|
||||
extern struct st_maria_plugin i_s_innodb_ft_being_deleted;
|
||||
extern struct st_maria_plugin i_s_innodb_ft_index_cache;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1997, 2013, 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
|
||||
|
|
@ -61,6 +61,7 @@ UNIV_INTERN my_bool srv_ibuf_disable_background_merge;
|
|||
#include "que0que.h"
|
||||
#include "srv0start.h" /* srv_shutdown_state */
|
||||
#include "ha_prototypes.h"
|
||||
#include "rem0cmp.h"
|
||||
|
||||
/* STRUCTURE OF AN INSERT BUFFER RECORD
|
||||
|
||||
|
|
@ -416,7 +417,7 @@ ibuf_tree_root_get(
|
|||
|
||||
ut_ad(page_get_space_id(root) == IBUF_SPACE_ID);
|
||||
ut_ad(page_get_page_no(root) == FSP_IBUF_TREE_ROOT_PAGE_NO);
|
||||
ut_ad(ibuf->empty == (page_get_n_recs(root) == 0));
|
||||
ut_ad(ibuf->empty == page_is_empty(root));
|
||||
|
||||
return(root);
|
||||
}
|
||||
|
|
@ -564,7 +565,7 @@ ibuf_init_at_db_start(void)
|
|||
ibuf_size_update(root, &mtr);
|
||||
mutex_exit(&ibuf_mutex);
|
||||
|
||||
ibuf->empty = (page_get_n_recs(root) == 0);
|
||||
ibuf->empty = page_is_empty(root);
|
||||
ibuf_mtr_commit(&mtr);
|
||||
|
||||
heap = mem_heap_create(450);
|
||||
|
|
@ -2567,7 +2568,7 @@ ulint
|
|||
ibuf_merge_pages(
|
||||
/*=============*/
|
||||
ulint* n_pages, /*!< out: number of pages to which merged */
|
||||
bool sync) /*!< in: TRUE if the caller wants to wait for
|
||||
bool sync) /*!< in: true if the caller wants to wait for
|
||||
the issued read with the highest tablespace
|
||||
address to complete */
|
||||
{
|
||||
|
|
@ -2589,7 +2590,7 @@ ibuf_merge_pages(
|
|||
|
||||
ut_ad(page_validate(btr_pcur_get_page(&pcur), ibuf->index));
|
||||
|
||||
if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
|
||||
if (page_is_empty(btr_pcur_get_page(&pcur))) {
|
||||
/* If a B-tree page is empty, it must be the root page
|
||||
and the whole B-tree must be empty. InnoDB does not
|
||||
allow empty B-tree pages other than the root. */
|
||||
|
|
@ -2633,7 +2634,8 @@ ibuf_get_table(
|
|||
{
|
||||
rw_lock_s_lock_func(&dict_operation_lock, 0, __FILE__, __LINE__);
|
||||
|
||||
dict_table_t* table = dict_table_open_on_id(table_id, FALSE, FALSE);
|
||||
dict_table_t* table = dict_table_open_on_id(
|
||||
table_id, FALSE, DICT_TABLE_OP_NORMAL);
|
||||
|
||||
rw_lock_s_unlock_gen(&dict_operation_lock, 0);
|
||||
|
||||
|
|
@ -2674,7 +2676,7 @@ ibuf_merge_space(
|
|||
ulint spaces[IBUF_MAX_N_PAGES_MERGED];
|
||||
ib_int64_t versions[IBUF_MAX_N_PAGES_MERGED];
|
||||
|
||||
if (page_get_n_recs(btr_pcur_get_page(&pcur)) == 0) {
|
||||
if (page_is_empty(btr_pcur_get_page(&pcur))) {
|
||||
/* If a B-tree page is empty, it must be the root page
|
||||
and the whole B-tree must be empty. InnoDB does not
|
||||
allow empty B-tree pages other than the root. */
|
||||
|
|
@ -2712,7 +2714,7 @@ ibuf_merge_space(
|
|||
#endif /* UNIV_DEBUG */
|
||||
|
||||
buf_read_ibuf_merge_pages(
|
||||
TRUE, spaces, versions, pages, *n_pages);
|
||||
true, spaces, versions, pages, *n_pages);
|
||||
}
|
||||
|
||||
return(sum_sizes);
|
||||
|
|
@ -3697,7 +3699,7 @@ fail_exit:
|
|||
ut_ad(page_get_page_no(root)
|
||||
== FSP_IBUF_TREE_ROOT_PAGE_NO);
|
||||
|
||||
ibuf->empty = (page_get_n_recs(root) == 0);
|
||||
ibuf->empty = page_is_empty(root);
|
||||
}
|
||||
} else {
|
||||
ut_ad(mode == BTR_MODIFY_TREE);
|
||||
|
|
@ -3726,7 +3728,7 @@ fail_exit:
|
|||
mutex_exit(&ibuf_pessimistic_insert_mutex);
|
||||
ibuf_size_update(root, &mtr);
|
||||
mutex_exit(&ibuf_mutex);
|
||||
ibuf->empty = (page_get_n_recs(root) == 0);
|
||||
ibuf->empty = page_is_empty(root);
|
||||
|
||||
block = btr_cur_get_block(cursor);
|
||||
ut_ad(buf_block_get_space(block) == IBUF_SPACE_ID);
|
||||
|
|
@ -3768,7 +3770,7 @@ func_exit:
|
|||
#ifdef UNIV_IBUF_DEBUG
|
||||
ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
|
||||
#endif
|
||||
buf_read_ibuf_merge_pages(FALSE, space_ids, space_versions,
|
||||
buf_read_ibuf_merge_pages(false, space_ids, space_versions,
|
||||
page_nos, n_stored);
|
||||
}
|
||||
|
||||
|
|
@ -3798,6 +3800,10 @@ ibuf_insert(
|
|||
/* Read the settable global variable ibuf_use only once in
|
||||
this function, so that we will have a consistent view of it. */
|
||||
ibuf_use_t use = ibuf_use;
|
||||
DBUG_ENTER("ibuf_insert");
|
||||
|
||||
DBUG_PRINT("ibuf", ("op: %d, space: %ld, page_no: %ld",
|
||||
op, space, page_no));
|
||||
|
||||
ut_ad(dtuple_check_typed(entry));
|
||||
ut_ad(ut_is_2pow(zip_size));
|
||||
|
|
@ -3812,7 +3818,7 @@ ibuf_insert(
|
|||
case IBUF_USE_NONE:
|
||||
case IBUF_USE_DELETE:
|
||||
case IBUF_USE_DELETE_MARK:
|
||||
return(FALSE);
|
||||
DBUG_RETURN(FALSE);
|
||||
case IBUF_USE_INSERT:
|
||||
case IBUF_USE_INSERT_DELETE_MARK:
|
||||
case IBUF_USE_ALL:
|
||||
|
|
@ -3825,7 +3831,7 @@ ibuf_insert(
|
|||
switch (use) {
|
||||
case IBUF_USE_NONE:
|
||||
case IBUF_USE_INSERT:
|
||||
return(FALSE);
|
||||
DBUG_RETURN(FALSE);
|
||||
case IBUF_USE_DELETE_MARK:
|
||||
case IBUF_USE_DELETE:
|
||||
case IBUF_USE_INSERT_DELETE_MARK:
|
||||
|
|
@ -3841,7 +3847,7 @@ ibuf_insert(
|
|||
case IBUF_USE_NONE:
|
||||
case IBUF_USE_INSERT:
|
||||
case IBUF_USE_INSERT_DELETE_MARK:
|
||||
return(FALSE);
|
||||
DBUG_RETURN(FALSE);
|
||||
case IBUF_USE_DELETE_MARK:
|
||||
case IBUF_USE_DELETE:
|
||||
case IBUF_USE_ALL:
|
||||
|
|
@ -3883,7 +3889,7 @@ check_watch:
|
|||
is being buffered, have this request executed
|
||||
directly on the page in the buffer pool after the
|
||||
buffered entries for this page have been merged. */
|
||||
return(FALSE);
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -3894,7 +3900,7 @@ skip_watch:
|
|||
>= page_get_free_space_of_empty(dict_table_is_comp(index->table))
|
||||
/ 2) {
|
||||
|
||||
return(FALSE);
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
|
||||
err = ibuf_insert_low(BTR_MODIFY_PREV, op, no_counter,
|
||||
|
|
@ -3911,20 +3917,21 @@ skip_watch:
|
|||
/* fprintf(stderr, "Ibuf insert for page no %lu of index %s\n",
|
||||
page_no, index->name); */
|
||||
#endif
|
||||
return(TRUE);
|
||||
DBUG_RETURN(TRUE);
|
||||
|
||||
} else {
|
||||
ut_a(err == DB_STRONG_FAIL || err == DB_TOO_BIG_RECORD);
|
||||
|
||||
return(FALSE);
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
During merge, inserts to an index page a secondary index entry extracted
|
||||
from the insert buffer. */
|
||||
from the insert buffer.
|
||||
@return newly inserted record */
|
||||
static __attribute__((nonnull))
|
||||
void
|
||||
rec_t*
|
||||
ibuf_insert_to_index_page_low(
|
||||
/*==========================*/
|
||||
const dtuple_t* entry, /*!< in: buffered entry to insert */
|
||||
|
|
@ -3943,22 +3950,31 @@ ibuf_insert_to_index_page_low(
|
|||
ulint zip_size;
|
||||
const page_t* bitmap_page;
|
||||
ulint old_bits;
|
||||
rec_t* rec;
|
||||
DBUG_ENTER("ibuf_insert_to_index_page_low");
|
||||
|
||||
if (page_cur_tuple_insert(
|
||||
page_cur, entry, index, offsets, &heap, 0, mtr) != NULL) {
|
||||
return;
|
||||
rec = page_cur_tuple_insert(page_cur, entry, index,
|
||||
offsets, &heap, 0, mtr);
|
||||
if (rec != NULL) {
|
||||
DBUG_RETURN(rec);
|
||||
}
|
||||
|
||||
/* Page reorganization or recompression should already have
|
||||
been attempted by page_cur_tuple_insert(). Besides, per
|
||||
ibuf_index_page_calc_free_zip() the page should not have been
|
||||
recompressed or reorganized. */
|
||||
ut_ad(!buf_block_get_page_zip(block));
|
||||
|
||||
/* If the record did not fit, reorganize */
|
||||
|
||||
btr_page_reorganize(block, index, mtr);
|
||||
page_cur_search(block, index, entry, PAGE_CUR_LE, page_cur);
|
||||
btr_page_reorganize(page_cur, index, mtr);
|
||||
|
||||
/* This time the record must fit */
|
||||
|
||||
if (page_cur_tuple_insert(page_cur, entry, index,
|
||||
offsets, &heap, 0, mtr) != NULL) {
|
||||
return;
|
||||
rec = page_cur_tuple_insert(page_cur, entry, index,
|
||||
offsets, &heap, 0, mtr);
|
||||
if (rec != NULL) {
|
||||
DBUG_RETURN(rec);
|
||||
}
|
||||
|
||||
page = buf_block_get_frame(block);
|
||||
|
|
@ -3992,6 +4008,7 @@ ibuf_insert_to_index_page_low(
|
|||
fputs("InnoDB: Submit a detailed bug report"
|
||||
" to http://bugs.mysql.com\n", stderr);
|
||||
ut_ad(0);
|
||||
DBUG_RETURN(NULL);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
|
|
@ -4014,6 +4031,13 @@ ibuf_insert_to_index_page(
|
|||
ulint* offsets;
|
||||
mem_heap_t* heap;
|
||||
|
||||
DBUG_ENTER("ibuf_insert_to_index_page");
|
||||
|
||||
DBUG_PRINT("ibuf", ("page_no: %ld", buf_block_get_page_no(block)));
|
||||
DBUG_PRINT("ibuf", ("index name: %s", index->name));
|
||||
DBUG_PRINT("ibuf", ("online status: %d",
|
||||
dict_index_get_online_status(index)));
|
||||
|
||||
ut_ad(ibuf_inside(mtr));
|
||||
ut_ad(dtuple_check_typed(entry));
|
||||
ut_ad(!buf_block_align(page)->index);
|
||||
|
|
@ -4057,7 +4081,7 @@ dump:
|
|||
"InnoDB: Submit a detailed bug report to"
|
||||
" http://bugs.mysql.com!\n", stderr);
|
||||
|
||||
return;
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
low_match = page_cur_search(block, index, entry,
|
||||
|
|
@ -4105,15 +4129,19 @@ dump:
|
|||
if (!row_upd_changes_field_size_or_external(index, offsets,
|
||||
update)
|
||||
&& (!page_zip || btr_cur_update_alloc_zip(
|
||||
page_zip, block, index,
|
||||
rec_offs_size(offsets), FALSE, mtr))) {
|
||||
page_zip, &page_cur, index, offsets,
|
||||
rec_offs_size(offsets), false, mtr))) {
|
||||
/* This is the easy case. Do something similar
|
||||
to btr_cur_update_in_place(). */
|
||||
rec = page_cur_get_rec(&page_cur);
|
||||
row_upd_rec_in_place(rec, index, offsets,
|
||||
update, page_zip);
|
||||
goto updated_in_place;
|
||||
}
|
||||
|
||||
/* btr_cur_update_alloc_zip() may have changed this */
|
||||
rec = page_cur_get_rec(&page_cur);
|
||||
|
||||
/* A collation may identify values that differ in
|
||||
storage length.
|
||||
Some examples (1 or 2 bytes):
|
||||
|
|
@ -4136,10 +4164,11 @@ dump:
|
|||
lock_rec_store_on_page_infimum(block, rec);
|
||||
page_cur_delete_rec(&page_cur, index, offsets, mtr);
|
||||
page_cur_move_to_prev(&page_cur);
|
||||
|
||||
ibuf_insert_to_index_page_low(entry, block, index,
|
||||
rec = ibuf_insert_to_index_page_low(entry, block, index,
|
||||
&offsets, heap, mtr,
|
||||
&page_cur);
|
||||
|
||||
ut_ad(!cmp_dtuple_rec(entry, rec, offsets));
|
||||
lock_rec_restore_from_page_infimum(block, rec, block);
|
||||
} else {
|
||||
offsets = NULL;
|
||||
|
|
@ -4147,9 +4176,10 @@ dump:
|
|||
&offsets, heap, mtr,
|
||||
&page_cur);
|
||||
}
|
||||
|
||||
updated_in_place:
|
||||
mem_heap_free(heap);
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
/****************************************************************//**
|
||||
|
|
@ -4378,7 +4408,7 @@ Deletes from ibuf the record on which pcur is positioned. If we have to
|
|||
resort to a pessimistic delete, this function commits mtr and closes
|
||||
the cursor.
|
||||
@return TRUE if mtr was committed and pcur closed in this operation */
|
||||
static
|
||||
static __attribute__((warn_unused_result))
|
||||
ibool
|
||||
ibuf_delete_rec(
|
||||
/*============*/
|
||||
|
|
@ -4411,7 +4441,7 @@ ibuf_delete_rec(
|
|||
btr_cur_set_deleted_flag_for_ibuf(
|
||||
btr_pcur_get_rec(pcur), NULL, TRUE, mtr);
|
||||
ibuf_mtr_commit(mtr);
|
||||
log_write_up_to(IB_ULONGLONG_MAX, LOG_WAIT_ALL_GROUPS, TRUE);
|
||||
log_write_up_to(LSN_MAX, LOG_WAIT_ALL_GROUPS, TRUE);
|
||||
DBUG_SUICIDE();
|
||||
}
|
||||
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
|
||||
|
|
@ -4420,7 +4450,7 @@ ibuf_delete_rec(
|
|||
0, mtr);
|
||||
|
||||
if (success) {
|
||||
if (UNIV_UNLIKELY(!page_get_n_recs(btr_pcur_get_page(pcur)))) {
|
||||
if (page_is_empty(btr_pcur_get_page(pcur))) {
|
||||
/* If a B-tree page is empty, it must be the root page
|
||||
and the whole B-tree must be empty. InnoDB does not
|
||||
allow empty B-tree pages other than the root. */
|
||||
|
|
@ -4433,7 +4463,7 @@ ibuf_delete_rec(
|
|||
/* ibuf->empty is protected by the root page latch.
|
||||
Before the deletion, it had to be FALSE. */
|
||||
ut_ad(!ibuf->empty);
|
||||
ibuf->empty = TRUE;
|
||||
ibuf->empty = true;
|
||||
}
|
||||
|
||||
#ifdef UNIV_IBUF_COUNT_DEBUG
|
||||
|
|
@ -4484,7 +4514,7 @@ ibuf_delete_rec(
|
|||
ibuf_size_update(root, mtr);
|
||||
mutex_exit(&ibuf_mutex);
|
||||
|
||||
ibuf->empty = (page_get_n_recs(root) == 0);
|
||||
ibuf->empty = page_is_empty(root);
|
||||
ibuf_btr_pcur_commit_specify_mtr(pcur, mtr);
|
||||
|
||||
func_exit:
|
||||
|
|
@ -4677,6 +4707,12 @@ ibuf_merge_or_delete_for_page(
|
|||
loop:
|
||||
ibuf_mtr_start(&mtr);
|
||||
|
||||
/* Position pcur in the insert buffer at the first entry for this
|
||||
index page */
|
||||
btr_pcur_open_on_user_rec(
|
||||
ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
|
||||
&pcur, &mtr);
|
||||
|
||||
if (block) {
|
||||
ibool success;
|
||||
|
||||
|
|
@ -4695,12 +4731,6 @@ loop:
|
|||
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE);
|
||||
}
|
||||
|
||||
/* Position pcur in the insert buffer at the first entry for this
|
||||
index page */
|
||||
btr_pcur_open_on_user_rec(
|
||||
ibuf->index, search_tuple, PAGE_CUR_GE, BTR_MODIFY_LEAF,
|
||||
&pcur, &mtr);
|
||||
|
||||
if (!btr_pcur_is_on_user_rec(&pcur)) {
|
||||
ut_ad(btr_pcur_is_after_last_in_tree(&pcur, &mtr));
|
||||
|
||||
|
|
@ -4785,6 +4815,16 @@ loop:
|
|||
== page_no);
|
||||
ut_ad(ibuf_rec_get_space(&mtr, rec) == space);
|
||||
|
||||
/* Mark the change buffer record processed,
|
||||
so that it will not be merged again in case
|
||||
the server crashes between the following
|
||||
mtr_commit() and the subsequent mtr_commit()
|
||||
of deleting the change buffer record. */
|
||||
|
||||
btr_cur_set_deleted_flag_for_ibuf(
|
||||
btr_pcur_get_rec(&pcur), NULL,
|
||||
TRUE, &mtr);
|
||||
|
||||
btr_pcur_store_position(&pcur, &mtr);
|
||||
ibuf_btr_pcur_commit_specify_mtr(&pcur, &mtr);
|
||||
|
||||
|
|
@ -4832,6 +4872,7 @@ loop:
|
|||
/* Deletion was pessimistic and mtr was committed:
|
||||
we start from the beginning again */
|
||||
|
||||
ut_ad(mtr.state == MTR_COMMITTED);
|
||||
goto loop;
|
||||
} else if (btr_pcur_is_after_last_on_page(&pcur)) {
|
||||
ibuf_mtr_commit(&mtr);
|
||||
|
|
@ -4962,6 +5003,7 @@ loop:
|
|||
/* Deletion was pessimistic and mtr was committed:
|
||||
we start from the beginning again */
|
||||
|
||||
ut_ad(mtr.state == MTR_COMMITTED);
|
||||
goto loop;
|
||||
}
|
||||
|
||||
|
|
@ -4991,13 +5033,13 @@ leave_loop:
|
|||
|
||||
/******************************************************************//**
|
||||
Looks if the insert buffer is empty.
|
||||
@return TRUE if empty */
|
||||
@return true if empty */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
bool
|
||||
ibuf_is_empty(void)
|
||||
/*===============*/
|
||||
{
|
||||
ibool is_empty;
|
||||
bool is_empty;
|
||||
const page_t* root;
|
||||
mtr_t mtr;
|
||||
|
||||
|
|
@ -5007,7 +5049,7 @@ ibuf_is_empty(void)
|
|||
root = ibuf_tree_root_get(&mtr);
|
||||
mutex_exit(&ibuf_mutex);
|
||||
|
||||
is_empty = (page_get_n_recs(root) == 0);
|
||||
is_empty = page_is_empty(root);
|
||||
ut_a(is_empty == ibuf->empty);
|
||||
ibuf_mtr_commit(&mtr);
|
||||
|
||||
|
|
|
|||
|
|
@ -728,7 +728,9 @@ ib_col_set_value(
|
|||
ib_tpl_t ib_tpl, /*!< in: tuple instance */
|
||||
ib_ulint_t col_no, /*!< in: column index in tuple */
|
||||
const void* src, /*!< in: data value */
|
||||
ib_ulint_t len); /*!< in: data value len */
|
||||
ib_ulint_t len, /*!< in: data value len */
|
||||
ib_bool_t need_cpy); /*!< in: if need memcpy */
|
||||
|
||||
|
||||
/*****************************************************************//**
|
||||
Get the size of the data available in the column the tuple.
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
@ -450,18 +450,48 @@ btr_root_raise_and_insert(
|
|||
__attribute__((nonnull, warn_unused_result));
|
||||
/*************************************************************//**
|
||||
Reorganizes an index page.
|
||||
IMPORTANT: if btr_page_reorganize() is invoked on a compressed leaf
|
||||
page of a non-clustered index, the caller must update the insert
|
||||
buffer free bits in the same mini-transaction in such a way that the
|
||||
modification will be redo-logged.
|
||||
@return TRUE on success, FALSE on failure */
|
||||
|
||||
IMPORTANT: On success, the caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index. This has to
|
||||
be done either within the same mini-transaction, or by invoking
|
||||
ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
|
||||
IBUF_BITMAP_FREE is unaffected by reorganization.
|
||||
|
||||
@retval true if the operation was successful
|
||||
@retval false if it is a compressed page, and recompression failed */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
bool
|
||||
btr_page_reorganize_low(
|
||||
/*====================*/
|
||||
bool recovery,/*!< in: true if called in recovery:
|
||||
locks should not be updated, i.e.,
|
||||
there cannot exist locks on the
|
||||
page, and a hash index should not be
|
||||
dropped: it cannot exist */
|
||||
ulint z_level,/*!< in: compression level to be used
|
||||
if dealing with compressed page */
|
||||
page_cur_t* cursor, /*!< in/out: page cursor */
|
||||
dict_index_t* index, /*!< in: the index tree of the page */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/*************************************************************//**
|
||||
Reorganizes an index page.
|
||||
|
||||
IMPORTANT: On success, the caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index. This has to
|
||||
be done either within the same mini-transaction, or by invoking
|
||||
ibuf_reset_free_bits() before mtr_commit(). On uncompressed pages,
|
||||
IBUF_BITMAP_FREE is unaffected by reorganization.
|
||||
|
||||
@retval true if the operation was successful
|
||||
@retval false if it is a compressed page, and recompression failed */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
btr_page_reorganize(
|
||||
/*================*/
|
||||
buf_block_t* block, /*!< in: page to be reorganized */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
mtr_t* mtr) /*!< in: mtr */
|
||||
page_cur_t* cursor, /*!< in/out: page cursor */
|
||||
dict_index_t* index, /*!< in: the index tree of the page */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull));
|
||||
/*************************************************************//**
|
||||
Decides if the page should be split at the convergence point of
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1994, 2013, 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
|
||||
|
|
@ -45,7 +45,11 @@ enum {
|
|||
BTR_KEEP_POS_FLAG = 8,
|
||||
/** the caller is creating the index or wants to bypass the
|
||||
index->info.online creation log */
|
||||
BTR_CREATE_FLAG = 16
|
||||
BTR_CREATE_FLAG = 16,
|
||||
/** the caller of btr_cur_optimistic_update() or
|
||||
btr_cur_update_in_place() will take care of
|
||||
updating IBUF_BITMAP_FREE */
|
||||
BTR_KEEP_IBUF_BITMAP = 32
|
||||
};
|
||||
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
|
|
@ -225,10 +229,11 @@ btr_cur_optimistic_insert(
|
|||
NULL */
|
||||
ulint n_ext, /*!< in: number of externally stored columns */
|
||||
que_thr_t* thr, /*!< in: query thread or NULL */
|
||||
mtr_t* mtr) /*!< in: mtr; if this function returns
|
||||
DB_SUCCESS on a leaf page of a secondary
|
||||
index in a compressed tablespace, the
|
||||
mtr must be committed before latching
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction;
|
||||
if this function returns DB_SUCCESS on
|
||||
a leaf page of a secondary index in a
|
||||
compressed tablespace, the caller must
|
||||
mtr_commit(mtr) before latching
|
||||
any further pages */
|
||||
__attribute__((nonnull(2,3,4,5,6,7,10), warn_unused_result));
|
||||
/*************************************************************//**
|
||||
|
|
@ -260,27 +265,48 @@ btr_cur_pessimistic_insert(
|
|||
NULL */
|
||||
ulint n_ext, /*!< in: number of externally stored columns */
|
||||
que_thr_t* thr, /*!< in: query thread or NULL */
|
||||
mtr_t* mtr) /*!< in: mtr */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull(2,3,4,5,6,7,10), warn_unused_result));
|
||||
/*************************************************************//**
|
||||
See if there is enough place in the page modification log to log
|
||||
an update-in-place.
|
||||
@return TRUE if enough place */
|
||||
|
||||
@retval false if out of space; IBUF_BITMAP_FREE will be reset
|
||||
outside mtr if the page was recompressed
|
||||
@retval true if enough place;
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE if this is
|
||||
a secondary index leaf page. This has to be done either within the
|
||||
same mini-transaction, or by invoking ibuf_reset_free_bits() before
|
||||
mtr_commit(mtr). */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
btr_cur_update_alloc_zip(
|
||||
/*=====================*/
|
||||
bool
|
||||
btr_cur_update_alloc_zip_func(
|
||||
/*==========================*/
|
||||
page_zip_des_t* page_zip,/*!< in/out: compressed page */
|
||||
buf_block_t* block, /*!< in/out: buffer page */
|
||||
dict_index_t* index, /*!< in: the index corresponding to the block */
|
||||
page_cur_t* cursor, /*!< in/out: B-tree page cursor */
|
||||
dict_index_t* index, /*!< in: the index corresponding to cursor */
|
||||
#ifdef UNIV_DEBUG
|
||||
ulint* offsets,/*!< in/out: offsets of the cursor record */
|
||||
#endif /* UNIV_DEBUG */
|
||||
ulint length, /*!< in: size needed */
|
||||
ibool create, /*!< in: TRUE=delete-and-insert,
|
||||
FALSE=update-in-place */
|
||||
mtr_t* mtr) /*!< in: mini-transaction */
|
||||
bool create, /*!< in: true=delete-and-insert,
|
||||
false=update-in-place */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
#ifdef UNIV_DEBUG
|
||||
# define btr_cur_update_alloc_zip(page_zip,cursor,index,offsets,len,cr,mtr) \
|
||||
btr_cur_update_alloc_zip_func(page_zip,cursor,index,offsets,len,cr,mtr)
|
||||
#else /* UNIV_DEBUG */
|
||||
# define btr_cur_update_alloc_zip(page_zip,cursor,index,offsets,len,cr,mtr) \
|
||||
btr_cur_update_alloc_zip_func(page_zip,cursor,index,len,cr,mtr)
|
||||
#endif /* UNIV_DEBUG */
|
||||
/*************************************************************//**
|
||||
Updates a record when the update causes no size changes in its fields.
|
||||
@return DB_SUCCESS or error number */
|
||||
@return locking or undo log related error code, or
|
||||
@retval DB_SUCCESS on success
|
||||
@retval DB_ZIP_OVERFLOW if there is not enough space left
|
||||
on the compressed page (IBUF_BITMAP_FREE was reset outside mtr) */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
btr_cur_update_in_place(
|
||||
|
|
@ -289,24 +315,28 @@ btr_cur_update_in_place(
|
|||
btr_cur_t* cursor, /*!< in: cursor on the record to update;
|
||||
cursor stays valid and positioned on the
|
||||
same record */
|
||||
const ulint* offsets,/*!< in: offsets on cursor->page_cur.rec */
|
||||
ulint* offsets,/*!< in/out: offsets on cursor->page_cur.rec */
|
||||
const upd_t* update, /*!< in: update vector */
|
||||
ulint cmpl_info,/*!< in: compiler info on secondary index
|
||||
updates */
|
||||
que_thr_t* thr, /*!< in: query thread, or NULL if
|
||||
appropriate flags are set */
|
||||
que_thr_t* thr, /*!< in: query thread */
|
||||
trx_id_t trx_id, /*!< in: transaction id */
|
||||
mtr_t* mtr) /*!< in: mtr; must be committed before
|
||||
latching any further pages */
|
||||
__attribute__((warn_unused_result, nonnull(2,3,4,8)));
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction; if this
|
||||
is a secondary index, the caller must
|
||||
mtr_commit(mtr) before latching any
|
||||
further pages */
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
/*************************************************************//**
|
||||
Tries to update a record on a page in an index tree. It is assumed that mtr
|
||||
holds an x-latch on the page. The operation does not succeed if there is too
|
||||
little space on the page or if the update would result in too empty a page,
|
||||
so that tree compression is recommended.
|
||||
@return DB_SUCCESS, or DB_OVERFLOW if the updated record does not fit,
|
||||
DB_UNDERFLOW if the page would become too empty, or DB_ZIP_OVERFLOW if
|
||||
there is not enough space left on the compressed page */
|
||||
@return error code, including
|
||||
@retval DB_SUCCESS on success
|
||||
@retval DB_OVERFLOW if the updated record does not fit
|
||||
@retval DB_UNDERFLOW if the page would become too empty
|
||||
@retval DB_ZIP_OVERFLOW if there is not enough space left
|
||||
on the compressed page */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
btr_cur_optimistic_update(
|
||||
|
|
@ -316,17 +346,18 @@ btr_cur_optimistic_update(
|
|||
cursor stays valid and positioned on the
|
||||
same record */
|
||||
ulint** offsets,/*!< out: offsets on cursor->page_cur.rec */
|
||||
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
|
||||
mem_heap_t** heap, /*!< in/out: pointer to NULL or memory heap */
|
||||
const upd_t* update, /*!< in: update vector; this must also
|
||||
contain trx id and roll ptr fields */
|
||||
ulint cmpl_info,/*!< in: compiler info on secondary index
|
||||
updates */
|
||||
que_thr_t* thr, /*!< in: query thread, or NULL if
|
||||
appropriate flags are set */
|
||||
que_thr_t* thr, /*!< in: query thread */
|
||||
trx_id_t trx_id, /*!< in: transaction id */
|
||||
mtr_t* mtr) /*!< in: mtr; must be committed before
|
||||
latching any further pages */
|
||||
__attribute__((warn_unused_result, nonnull(2,3,4,5,9)));
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction; if this
|
||||
is a secondary index, the caller must
|
||||
mtr_commit(mtr) before latching any
|
||||
further pages */
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
/*************************************************************//**
|
||||
Performs an update of a record on a page of a tree. It is assumed
|
||||
that mtr holds an x-latch on the tree and on the cursor page. If the
|
||||
|
|
@ -356,12 +387,11 @@ btr_cur_pessimistic_update(
|
|||
the values in update vector have no effect */
|
||||
ulint cmpl_info,/*!< in: compiler info on secondary index
|
||||
updates */
|
||||
que_thr_t* thr, /*!< in: query thread, or NULL if
|
||||
appropriate flags are set */
|
||||
que_thr_t* thr, /*!< in: query thread */
|
||||
trx_id_t trx_id, /*!< in: transaction id */
|
||||
mtr_t* mtr) /*!< in: mtr; must be committed before
|
||||
latching any further pages */
|
||||
__attribute__((warn_unused_result, nonnull(2,3,4,5,6,7,11)));
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction; must be committed
|
||||
before latching any further pages */
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
/***********************************************************//**
|
||||
Marks a clustered index record deleted. Writes an undo log record to
|
||||
undo log on this delete marking. Writes in the trx id field the id
|
||||
|
|
@ -377,8 +407,8 @@ btr_cur_del_mark_set_clust_rec(
|
|||
dict_index_t* index, /*!< in: clustered index of the record */
|
||||
const ulint* offsets,/*!< in: rec_get_offsets(rec) */
|
||||
que_thr_t* thr, /*!< in: query thread */
|
||||
mtr_t* mtr) /*!< in: mtr */
|
||||
__attribute__((nonnull));
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/***********************************************************//**
|
||||
Sets a secondary index record delete mark to TRUE or FALSE.
|
||||
@return DB_SUCCESS, DB_LOCK_WAIT, or error number */
|
||||
|
|
@ -390,7 +420,8 @@ btr_cur_del_mark_set_sec_rec(
|
|||
btr_cur_t* cursor, /*!< in: cursor */
|
||||
ibool val, /*!< in: value to set */
|
||||
que_thr_t* thr, /*!< in: query thread */
|
||||
mtr_t* mtr); /*!< in: mtr */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/*************************************************************//**
|
||||
Tries to compress a page of the tree if it seems useful. It is assumed
|
||||
that mtr holds an x-latch on the tree and on the cursor page. To avoid
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -104,9 +104,7 @@ extern buf_block_t* back_block2; /*!< second block, for page reorganize */
|
|||
|
||||
The enumeration values must be 0..7. */
|
||||
enum buf_page_state {
|
||||
BUF_BLOCK_ZIP_FREE = 0, /*!< contains a free
|
||||
compressed page */
|
||||
BUF_BLOCK_POOL_WATCH = 0, /*!< a sentinel for the buffer pool
|
||||
BUF_BLOCK_POOL_WATCH, /*!< a sentinel for the buffer pool
|
||||
watch, element of buf_pool->watch[] */
|
||||
BUF_BLOCK_ZIP_PAGE, /*!< contains a clean
|
||||
compressed page */
|
||||
|
|
@ -897,7 +895,7 @@ buf_page_get_mutex(
|
|||
Get the flush type of a page.
|
||||
@return flush type */
|
||||
UNIV_INLINE
|
||||
enum buf_flush
|
||||
buf_flush_t
|
||||
buf_page_get_flush_type(
|
||||
/*====================*/
|
||||
const buf_page_t* bpage) /*!< in: buffer page */
|
||||
|
|
@ -909,7 +907,7 @@ void
|
|||
buf_page_set_flush_type(
|
||||
/*====================*/
|
||||
buf_page_t* bpage, /*!< in: buffer page */
|
||||
enum buf_flush flush_type); /*!< in: flush type */
|
||||
buf_flush_t flush_type); /*!< in: flush type */
|
||||
/*********************************************************************//**
|
||||
Map a block to a file page. */
|
||||
UNIV_INLINE
|
||||
|
|
@ -1451,7 +1449,7 @@ struct buf_page_t{
|
|||
unsigned flush_type:2; /*!< if this block is currently being
|
||||
flushed to disk, this tells the
|
||||
flush_type.
|
||||
@see enum buf_flush */
|
||||
@see buf_flush_t */
|
||||
unsigned io_fix:2; /*!< type of pending I/O operation;
|
||||
also protected by buf_pool->mutex
|
||||
@see enum buf_io_fix */
|
||||
|
|
@ -1495,7 +1493,6 @@ struct buf_page_t{
|
|||
- BUF_BLOCK_FILE_PAGE: flush_list
|
||||
- BUF_BLOCK_ZIP_DIRTY: flush_list
|
||||
- BUF_BLOCK_ZIP_PAGE: zip_clean
|
||||
- BUF_BLOCK_ZIP_FREE: zip_free[]
|
||||
|
||||
If bpage is part of flush_list
|
||||
then the node pointers are
|
||||
|
|
@ -1729,6 +1726,26 @@ Compute the hash fold value for blocks in buf_pool->zip_hash. */
|
|||
#define BUF_POOL_ZIP_FOLD_BPAGE(b) BUF_POOL_ZIP_FOLD((buf_block_t*) (b))
|
||||
/* @} */
|
||||
|
||||
/** Struct that is embedded in the free zip blocks */
|
||||
struct buf_buddy_free_t {
|
||||
union {
|
||||
ulint size; /*!< size of the block */
|
||||
byte bytes[FIL_PAGE_DATA];
|
||||
/*!< stamp[FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID]
|
||||
== BUF_BUDDY_FREE_STAMP denotes a free
|
||||
block. If the space_id field of buddy
|
||||
block != BUF_BUDDY_FREE_STAMP, the block
|
||||
is not in any zip_free list. If the
|
||||
space_id is BUF_BUDDY_FREE_STAMP then
|
||||
stamp[0] will contain the
|
||||
buddy block size. */
|
||||
} stamp;
|
||||
|
||||
buf_page_t bpage; /*!< Embedded bpage descriptor */
|
||||
UT_LIST_NODE_T(buf_buddy_free_t) list;
|
||||
/*!< Node of zip_free list */
|
||||
};
|
||||
|
||||
/** @brief The buffer pool statistics structure. */
|
||||
struct buf_pool_stat_t{
|
||||
ulint n_page_gets; /*!< number of page gets performed;
|
||||
|
|
@ -1839,7 +1856,12 @@ struct buf_pool_t{
|
|||
and bpage::list pointers when
|
||||
the bpage is on flush_list. It
|
||||
also protects writes to
|
||||
bpage::oldest_modification */
|
||||
bpage::oldest_modification and
|
||||
flush_list_hp */
|
||||
const buf_page_t* flush_list_hp;/*!< "hazard pointer"
|
||||
used during scan of flush_list
|
||||
while doing flush list batch.
|
||||
Protected by flush_list_mutex */
|
||||
UT_LIST_BASE_NODE_T(buf_page_t) flush_list;
|
||||
/*!< base node of the modified block
|
||||
list */
|
||||
|
|
@ -1925,7 +1947,7 @@ struct buf_pool_t{
|
|||
UT_LIST_BASE_NODE_T(buf_page_t) zip_clean;
|
||||
/*!< unmodified compressed pages */
|
||||
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
|
||||
UT_LIST_BASE_NODE_T(buf_page_t) zip_free[BUF_BUDDY_SIZES_MAX];
|
||||
UT_LIST_BASE_NODE_T(buf_buddy_free_t) zip_free[BUF_BUDDY_SIZES_MAX];
|
||||
/*!< buddy free lists */
|
||||
|
||||
buf_page_t* watch;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2008, Google Inc.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
|
|
@ -205,7 +205,7 @@ buf_page_get_state(
|
|||
|
||||
#ifdef UNIV_DEBUG
|
||||
switch (state) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
|
|
@ -245,7 +245,7 @@ buf_page_set_state(
|
|||
enum buf_page_state old_state = buf_page_get_state(bpage);
|
||||
|
||||
switch (old_state) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
ut_error;
|
||||
break;
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
|
|
@ -300,9 +300,7 @@ buf_page_in_file(
|
|||
const buf_page_t* bpage) /*!< in: pointer to control block */
|
||||
{
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
/* This is a free page in buf_pool->zip_free[].
|
||||
Such pages should only be accessed by the buddy allocator. */
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
ut_error;
|
||||
break;
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
|
|
@ -347,7 +345,7 @@ buf_page_get_mutex(
|
|||
buf_pool_t* buf_pool = buf_pool_from_bpage(bpage);
|
||||
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
ut_error;
|
||||
return(NULL);
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
|
|
@ -362,12 +360,12 @@ buf_page_get_mutex(
|
|||
Get the flush type of a page.
|
||||
@return flush type */
|
||||
UNIV_INLINE
|
||||
enum buf_flush
|
||||
buf_flush_t
|
||||
buf_page_get_flush_type(
|
||||
/*====================*/
|
||||
const buf_page_t* bpage) /*!< in: buffer page */
|
||||
{
|
||||
enum buf_flush flush_type = (enum buf_flush) bpage->flush_type;
|
||||
buf_flush_t flush_type = (buf_flush_t) bpage->flush_type;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
switch (flush_type) {
|
||||
|
|
@ -389,7 +387,7 @@ void
|
|||
buf_page_set_flush_type(
|
||||
/*====================*/
|
||||
buf_page_t* bpage, /*!< in: buffer page */
|
||||
enum buf_flush flush_type) /*!< in: flush type */
|
||||
buf_flush_t flush_type) /*!< in: flush type */
|
||||
{
|
||||
bpage->flush_type = flush_type;
|
||||
ut_ad(buf_page_get_flush_type(bpage) == flush_type);
|
||||
|
|
@ -666,7 +664,7 @@ buf_block_get_frame(
|
|||
ut_ad(block);
|
||||
|
||||
switch (buf_block_get_state(block)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
|
|
@ -1311,7 +1309,7 @@ buf_page_release_zip(
|
|||
bpage->buf_fix_count--;
|
||||
mutex_exit(&block->mutex);
|
||||
return;
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_POOL_WATCH:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
|
|
|
|||
|
|
@ -63,12 +63,13 @@ void
|
|||
buf_dblwr_free(void);
|
||||
/*================*/
|
||||
/********************************************************************//**
|
||||
Updates the doublewrite buffer when an IO request that is part of an
|
||||
LRU or flush batch is completed. */
|
||||
Updates the doublewrite buffer when an IO request is completed. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
buf_dblwr_update(void);
|
||||
/*==================*/
|
||||
buf_dblwr_update(
|
||||
/*=============*/
|
||||
const buf_page_t* bpage, /*!< in: buffer block descriptor */
|
||||
buf_flush_t flush_type);/*!< in: flush type */
|
||||
/****************************************************************//**
|
||||
Determines if a page number is located inside the doublewrite buffer.
|
||||
@return TRUE if the location is inside the two blocks of the
|
||||
|
|
@ -109,36 +110,41 @@ UNIV_INTERN
|
|||
void
|
||||
buf_dblwr_write_single_page(
|
||||
/*========================*/
|
||||
buf_page_t* bpage); /*!< in: buffer block to write */
|
||||
buf_page_t* bpage, /*!< in: buffer block to write */
|
||||
bool sync); /*!< in: true if sync IO requested */
|
||||
|
||||
/** Doublewrite control struct */
|
||||
struct buf_dblwr_t{
|
||||
ib_mutex_t mutex; /*!< mutex protecting the first_free field and
|
||||
write_buf */
|
||||
ib_mutex_t mutex; /*!< mutex protecting the first_free
|
||||
field and write_buf */
|
||||
ulint block1; /*!< the page number of the first
|
||||
doublewrite block (64 pages) */
|
||||
ulint block2; /*!< page number of the second block */
|
||||
ulint first_free; /*!< first free position in write_buf measured
|
||||
in units of UNIV_PAGE_SIZE */
|
||||
ulint s_reserved; /*!< number of slots currently reserved
|
||||
for single page flushes. */
|
||||
ulint b_reserved; /*!< number of slots currently reserved
|
||||
ulint first_free;/*!< first free position in write_buf
|
||||
measured in units of UNIV_PAGE_SIZE */
|
||||
ulint b_reserved;/*!< number of slots currently reserved
|
||||
for batch flush. */
|
||||
ibool* in_use; /*!< flag used to indicate if a slot is
|
||||
os_event_t b_event;/*!< event where threads wait for a
|
||||
batch flush to end. */
|
||||
ulint s_reserved;/*!< number of slots currently
|
||||
reserved for single page flushes. */
|
||||
os_event_t s_event;/*!< event where threads wait for a
|
||||
single page flush slot. */
|
||||
bool* in_use; /*!< flag used to indicate if a slot is
|
||||
in use. Only used for single page
|
||||
flushes. */
|
||||
ibool batch_running; /*!< set to TRUE if currently a batch
|
||||
bool batch_running;/*!< set to TRUE if currently a batch
|
||||
is being written from the doublewrite
|
||||
buffer. */
|
||||
byte* write_buf; /*!< write buffer used in writing to the
|
||||
byte* write_buf;/*!< write buffer used in writing to the
|
||||
doublewrite buffer, aligned to an
|
||||
address divisible by UNIV_PAGE_SIZE
|
||||
(which is required by Windows aio) */
|
||||
byte* write_buf_unaligned;
|
||||
/*!< pointer to write_buf, but unaligned */
|
||||
buf_page_t**
|
||||
buf_block_arr; /*!< array to store pointers to the buffer
|
||||
blocks which have been cached to write_buf */
|
||||
byte* write_buf_unaligned;/*!< pointer to write_buf,
|
||||
but unaligned */
|
||||
buf_page_t** buf_block_arr;/*!< array to store pointers to
|
||||
the buffer blocks which have been
|
||||
cached to write_buf */
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -87,13 +87,6 @@ buf_flush_page_try(
|
|||
buf_block_t* block) /*!< in/out: buffer control block */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
# endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
|
||||
/********************************************************************//**
|
||||
Flush a batch of writes to the datafiles that have already been
|
||||
written by the OS. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
buf_flush_sync_datafiles(void);
|
||||
/*==========================*/
|
||||
/*******************************************************************//**
|
||||
This utility flushes dirty blocks from the end of the flush list of
|
||||
all buffer pool instances.
|
||||
|
|
@ -136,7 +129,7 @@ void
|
|||
buf_flush_wait_batch_end(
|
||||
/*=====================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
enum buf_flush type); /*!< in: BUF_FLUSH_LRU
|
||||
buf_flush_t type); /*!< in: BUF_FLUSH_LRU
|
||||
or BUF_FLUSH_LIST */
|
||||
/******************************************************************//**
|
||||
Waits until a flush batch of the given type ends. This is called by
|
||||
|
|
@ -147,7 +140,7 @@ void
|
|||
buf_flush_wait_batch_end_wait_only(
|
||||
/*===============================*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
enum buf_flush type); /*!< in: BUF_FLUSH_LRU
|
||||
buf_flush_t type); /*!< in: BUF_FLUSH_LRU
|
||||
or BUF_FLUSH_LIST */
|
||||
/********************************************************************//**
|
||||
This function should be called at a mini-transaction commit, if a page was
|
||||
|
|
@ -248,8 +241,20 @@ buf_flush_page(
|
|||
/*===========*/
|
||||
buf_pool_t* buf_pool, /*!< in: buffer pool instance */
|
||||
buf_page_t* bpage, /*!< in: buffer control block */
|
||||
buf_flush flush_type) /*!< in: type of flush */
|
||||
buf_flush_t flush_type, /*!< in: type of flush */
|
||||
bool sync) /*!< in: true if sync IO request */
|
||||
__attribute__((nonnull));
|
||||
/********************************************************************//**
|
||||
Returns true if the block is modified and ready for flushing.
|
||||
@return true if can flush immediately */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
buf_flush_ready_for_flush(
|
||||
/*======================*/
|
||||
buf_page_t* bpage, /*!< in: buffer control block, must be
|
||||
buf_page_in_file(bpage) */
|
||||
buf_flush_t flush_type)/*!< in: type of flush */
|
||||
__attribute__((warn_unused_result));
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/******************************************************************//**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -79,19 +79,19 @@ buf_LRU_insert_zip_clean(
|
|||
Try to free a block. If bpage is a descriptor of a compressed-only
|
||||
page, the descriptor object will be freed as well.
|
||||
|
||||
NOTE: If this function returns TRUE, it will temporarily
|
||||
NOTE: If this function returns true, it will temporarily
|
||||
release buf_pool->mutex. Furthermore, the page frame will no longer be
|
||||
accessible via bpage.
|
||||
|
||||
The caller must hold buf_pool->mutex and must not hold any
|
||||
buf_page_get_mutex() when calling this function.
|
||||
@return TRUE if freed, FALSE otherwise. */
|
||||
@return true if freed, false otherwise. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
buf_LRU_free_block(
|
||||
/*===============*/
|
||||
bool
|
||||
buf_LRU_free_page(
|
||||
/*==============*/
|
||||
buf_page_t* bpage, /*!< in: block to be freed */
|
||||
ibool zip) /*!< in: TRUE if should remove also the
|
||||
bool zip) /*!< in: true if should remove also the
|
||||
compressed page of an uncompressed page */
|
||||
__attribute__((nonnull));
|
||||
/******************************************************************//**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2009, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -119,7 +119,7 @@ UNIV_INTERN
|
|||
void
|
||||
buf_read_ibuf_merge_pages(
|
||||
/*======================*/
|
||||
ibool sync, /*!< in: TRUE if the caller
|
||||
bool sync, /*!< in: true if the caller
|
||||
wants this function to wait
|
||||
for the highest address page
|
||||
to get read in, before this
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -45,7 +45,7 @@ struct buf_dblwr_t;
|
|||
typedef byte buf_frame_t;
|
||||
|
||||
/** Flags for flush types */
|
||||
enum buf_flush {
|
||||
enum buf_flush_t {
|
||||
BUF_FLUSH_LRU = 0, /*!< flush via the LRU list */
|
||||
BUF_FLUSH_LIST, /*!< flush via the flush list
|
||||
of dirty blocks */
|
||||
|
|
|
|||
|
|
@ -124,6 +124,9 @@ enum dberr_t {
|
|||
during online index creation */
|
||||
|
||||
DB_IO_ERROR, /*!< Generic IO error */
|
||||
DB_IDENTIFIER_TOO_LONG, /*!< Identifier name too long */
|
||||
DB_FTS_EXCEED_RESULT_CACHE_LIMIT, /*!< FTS query memory
|
||||
exceeds result cache limit */
|
||||
|
||||
/* The following are partial failure codes */
|
||||
DB_FAIL = 1000,
|
||||
|
|
|
|||
|
|
@ -111,6 +111,20 @@ dberr_t
|
|||
dict_create_or_check_foreign_constraint_tables(void);
|
||||
/*================================================*/
|
||||
/********************************************************************//**
|
||||
Generate a foreign key constraint name when it was not named by the user.
|
||||
A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER,
|
||||
where the numbers start from 1, and are given locally for this table, that is,
|
||||
the number is not global, as it used to be before MySQL 4.0.18. */
|
||||
UNIV_INLINE
|
||||
dberr_t
|
||||
dict_create_add_foreign_id(
|
||||
/*=======================*/
|
||||
ulint* id_nr, /*!< in/out: number to use in id generation;
|
||||
incremented if used */
|
||||
const char* name, /*!< in: table name */
|
||||
dict_foreign_t* foreign)/*!< in/out: foreign key */
|
||||
__attribute__((nonnull));
|
||||
/********************************************************************//**
|
||||
Adds foreign key definitions to data dictionary tables in the database. We
|
||||
look at table->foreign_list, and also generate names to constraints that were
|
||||
not named by the user. A generated constraint has a name of the format
|
||||
|
|
@ -158,24 +172,14 @@ dict_create_add_tablespace_to_dictionary(
|
|||
bool commit); /*!< in: if true then commit the
|
||||
transaction */
|
||||
/********************************************************************//**
|
||||
Table create node structure */
|
||||
|
||||
/********************************************************************//**
|
||||
Add a single foreign key definition to the data dictionary tables in the
|
||||
database. We also generate names to constraints that were not named by the
|
||||
user. A generated constraint has a name of the format
|
||||
databasename/tablename_ibfk_NUMBER, where the numbers start from 1, and
|
||||
are given locally for this table, that is, the number is not global, as in
|
||||
the old format constraints < 4.0.18 it used to be.
|
||||
Add a foreign key definition to the data dictionary tables.
|
||||
@return error code or DB_SUCCESS */
|
||||
UNIV_INTERN
|
||||
dberr_t
|
||||
dict_create_add_foreign_to_dictionary(
|
||||
/*==================================*/
|
||||
ulint* id_nr, /*!< in/out: number to use in id generation;
|
||||
incremented if used */
|
||||
dict_table_t* table, /*!< in: table */
|
||||
dict_foreign_t* foreign,/*!< in: foreign */
|
||||
const char* name, /*!< in: table name */
|
||||
const dict_foreign_t* foreign,/*!< in: foreign key */
|
||||
trx_t* trx) /*!< in/out: dictionary transaction */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2012, 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
|
||||
|
|
@ -23,3 +23,76 @@ Database object creation
|
|||
Created 1/8/1996 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "mem0mem.h"
|
||||
|
||||
/*********************************************************************//**
|
||||
Checks if a table name contains the string "/#sql" which denotes temporary
|
||||
tables in MySQL.
|
||||
@return true if temporary table */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
row_is_mysql_tmp_table_name(
|
||||
/*========================*/
|
||||
const char* name) __attribute__((warn_unused_result));
|
||||
/*!< in: table name in the form
|
||||
'database/tablename' */
|
||||
|
||||
|
||||
/********************************************************************//**
|
||||
Generate a foreign key constraint name when it was not named by the user.
|
||||
A generated constraint has a name of the format dbname/tablename_ibfk_NUMBER,
|
||||
where the numbers start from 1, and are given locally for this table, that is,
|
||||
the number is not global, as it used to be before MySQL 4.0.18. */
|
||||
UNIV_INLINE
|
||||
dberr_t
|
||||
dict_create_add_foreign_id(
|
||||
/*=======================*/
|
||||
ulint* id_nr, /*!< in/out: number to use in id generation;
|
||||
incremented if used */
|
||||
const char* name, /*!< in: table name */
|
||||
dict_foreign_t* foreign)/*!< in/out: foreign key */
|
||||
{
|
||||
if (foreign->id == NULL) {
|
||||
/* Generate a new constraint id */
|
||||
ulint namelen = strlen(name);
|
||||
char* id = static_cast<char*>(
|
||||
mem_heap_alloc(foreign->heap,
|
||||
namelen + 20));
|
||||
|
||||
if (row_is_mysql_tmp_table_name(name)) {
|
||||
|
||||
/* no overflow if number < 1e13 */
|
||||
sprintf(id, "%s_ibfk_%lu", name,
|
||||
(ulong) (*id_nr)++);
|
||||
} else {
|
||||
char table_name[MAX_TABLE_NAME_LEN + 20] = "";
|
||||
uint errors = 0;
|
||||
|
||||
strncpy(table_name, name,
|
||||
MAX_TABLE_NAME_LEN + 20);
|
||||
|
||||
innobase_convert_to_system_charset(
|
||||
strchr(table_name, '/') + 1,
|
||||
strchr(name, '/') + 1,
|
||||
MAX_TABLE_NAME_LEN, &errors);
|
||||
|
||||
if (errors) {
|
||||
strncpy(table_name, name,
|
||||
MAX_TABLE_NAME_LEN + 20);
|
||||
}
|
||||
|
||||
/* no overflow if number < 1e13 */
|
||||
sprintf(id, "%s_ibfk_%lu", table_name,
|
||||
(ulong) (*id_nr)++);
|
||||
|
||||
if (innobase_check_identifier_length(
|
||||
strchr(id,'/') + 1)) {
|
||||
return(DB_IDENTIFIER_TOO_LONG);
|
||||
}
|
||||
}
|
||||
foreign->id = id;
|
||||
}
|
||||
|
||||
return(DB_SUCCESS);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
@ -108,6 +108,18 @@ dict_remove_db_name(
|
|||
const char* name) /*!< in: table name in the form
|
||||
dbname '/' tablename */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
|
||||
/** Operation to perform when opening a table */
|
||||
enum dict_table_op_t {
|
||||
/** Expect the tablespace to exist. */
|
||||
DICT_TABLE_OP_NORMAL = 0,
|
||||
/** Drop any orphan indexes after an aborted online index creation */
|
||||
DICT_TABLE_OP_DROP_ORPHAN,
|
||||
/** Silently load the tablespace if it does not exist,
|
||||
and do not load the definitions of incomplete indexes. */
|
||||
DICT_TABLE_OP_LOAD_TABLESPACE
|
||||
};
|
||||
|
||||
/**********************************************************************//**
|
||||
Returns a table object based on table id.
|
||||
@return table, NULL if does not exist */
|
||||
|
|
@ -117,9 +129,7 @@ dict_table_open_on_id(
|
|||
/*==================*/
|
||||
table_id_t table_id, /*!< in: table id */
|
||||
ibool dict_locked, /*!< in: TRUE=data dictionary locked */
|
||||
ibool try_drop) /*!< in: TRUE=try to drop any orphan
|
||||
indexes after an aborted online
|
||||
index creation */
|
||||
dict_table_op_t table_op) /*!< in: operation to perform */
|
||||
__attribute__((warn_unused_result));
|
||||
/********************************************************************//**
|
||||
Decrements the count of open handles to a table. */
|
||||
|
|
@ -408,10 +418,17 @@ UNIV_INTERN
|
|||
dberr_t
|
||||
dict_foreign_add_to_cache(
|
||||
/*======================*/
|
||||
dict_foreign_t* foreign, /*!< in, own: foreign key constraint */
|
||||
ibool check_charsets) /*!< in: TRUE=check charset
|
||||
dict_foreign_t* foreign,
|
||||
/*!< in, own: foreign key constraint */
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL to use
|
||||
foreign->foreign_table->col_names */
|
||||
bool check_charsets,
|
||||
/*!< in: whether to check charset
|
||||
compatibility */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
dict_err_ignore_t ignore_err)
|
||||
/*!< in: error to be ignored */
|
||||
__attribute__((nonnull(1), warn_unused_result));
|
||||
/*********************************************************************//**
|
||||
Check if the index is referenced by a foreign key, if TRUE return the
|
||||
matching instance NULL otherwise.
|
||||
|
|
@ -435,15 +452,18 @@ dict_table_is_referenced_by_foreign_key(
|
|||
__attribute__((nonnull, warn_unused_result));
|
||||
/**********************************************************************//**
|
||||
Replace the index passed in with another equivalent index in the
|
||||
foreign key lists of the table. */
|
||||
foreign key lists of the table.
|
||||
@return whether all replacements were found */
|
||||
UNIV_INTERN
|
||||
void
|
||||
bool
|
||||
dict_foreign_replace_index(
|
||||
/*=======================*/
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
const dict_index_t* index, /*!< in: index to be replaced */
|
||||
const trx_t* trx) /*!< in: transaction handle */
|
||||
__attribute__((nonnull));
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
const dict_index_t* index) /*!< in: index to be replaced */
|
||||
__attribute__((nonnull(1,3), warn_unused_result));
|
||||
/**********************************************************************//**
|
||||
Determines whether a string starts with the specified keyword.
|
||||
@return TRUE if str starts with keyword */
|
||||
|
|
@ -544,13 +564,16 @@ dict_index_t*
|
|||
dict_foreign_find_index(
|
||||
/*====================*/
|
||||
const dict_table_t* table, /*!< in: table */
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
const char** columns,/*!< in: array of column names */
|
||||
ulint n_cols, /*!< in: number of columns */
|
||||
const dict_index_t* types_idx,
|
||||
/*!< in: NULL or an index
|
||||
whose types the column types
|
||||
must match */
|
||||
ibool check_charsets,
|
||||
bool check_charsets,
|
||||
/*!< in: whether to check
|
||||
charsets. only has an effect
|
||||
if types_idx != NULL */
|
||||
|
|
@ -558,7 +581,7 @@ dict_foreign_find_index(
|
|||
/*!< in: nonzero if none of
|
||||
the columns must be declared
|
||||
NOT NULL */
|
||||
__attribute__((nonnull(1,2), warn_unused_result));
|
||||
__attribute__((nonnull(1,3), warn_unused_result));
|
||||
/**********************************************************************//**
|
||||
Returns a column's name.
|
||||
@return column name. NOTE: not guaranteed to stay valid if table is
|
||||
|
|
@ -624,6 +647,9 @@ bool
|
|||
dict_foreign_qualify_index(
|
||||
/*====================*/
|
||||
const dict_table_t* table, /*!< in: table */
|
||||
const char** col_names,
|
||||
/*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
const char** columns,/*!< in: array of column names */
|
||||
ulint n_cols, /*!< in: number of columns */
|
||||
const dict_index_t* index, /*!< in: index to check */
|
||||
|
|
@ -631,7 +657,7 @@ dict_foreign_qualify_index(
|
|||
/*!< in: NULL or an index
|
||||
whose types the column types
|
||||
must match */
|
||||
ibool check_charsets,
|
||||
bool check_charsets,
|
||||
/*!< in: whether to check
|
||||
charsets. only has an effect
|
||||
if types_idx != NULL */
|
||||
|
|
@ -639,7 +665,7 @@ dict_foreign_qualify_index(
|
|||
/*!< in: nonzero if none of
|
||||
the columns must be declared
|
||||
NOT NULL */
|
||||
__attribute__((nonnull(1,2), warn_unused_result));
|
||||
__attribute__((nonnull(1,3), warn_unused_result));
|
||||
#ifdef UNIV_DEBUG
|
||||
/********************************************************************//**
|
||||
Gets the first index on the table (the clustered index).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -58,6 +58,18 @@ enum dict_table_info_t {
|
|||
is in the cache, if so, return it */
|
||||
};
|
||||
|
||||
/** Check type for dict_check_tablespaces_and_store_max_id() */
|
||||
enum dict_check_t {
|
||||
/** No user tablespaces have been opened
|
||||
(no crash recovery, no transactions recovered). */
|
||||
DICT_CHECK_NONE_LOADED = 0,
|
||||
/** Some user tablespaces may have been opened
|
||||
(no crash recovery; recovered table locks for transactions). */
|
||||
DICT_CHECK_SOME_LOADED,
|
||||
/** All user tablespaces have been opened (crash recovery). */
|
||||
DICT_CHECK_ALL_LOADED
|
||||
};
|
||||
|
||||
/********************************************************************//**
|
||||
In a crash recovery we already have all the tablespace objects created.
|
||||
This function compares the space id information in the InnoDB data dictionary
|
||||
|
|
@ -70,7 +82,7 @@ UNIV_INTERN
|
|||
void
|
||||
dict_check_tablespaces_and_store_max_id(
|
||||
/*====================================*/
|
||||
ibool in_crash_recovery); /*!< in: are we doing a crash recovery */
|
||||
dict_check_t dict_check); /*!< in: how to check */
|
||||
/********************************************************************//**
|
||||
Finds the first table name in the given database.
|
||||
@return own: table name, NULL if does not exist; the caller must free
|
||||
|
|
@ -199,7 +211,9 @@ UNIV_INTERN
|
|||
dict_table_t*
|
||||
dict_load_table_on_id(
|
||||
/*==================*/
|
||||
table_id_t table_id); /*!< in: table id */
|
||||
table_id_t table_id, /*!< in: table id */
|
||||
dict_err_ignore_t ignore_err); /*!< in: errors to ignore
|
||||
when loading the table */
|
||||
/********************************************************************//**
|
||||
This function is called when the database is booted.
|
||||
Loads system table index definitions except for the clustered index which
|
||||
|
|
@ -221,11 +235,15 @@ dberr_t
|
|||
dict_load_foreigns(
|
||||
/*===============*/
|
||||
const char* table_name, /*!< in: table name */
|
||||
ibool check_recursive,/*!< in: Whether to check recursive
|
||||
load of tables chained by FK */
|
||||
ibool check_charsets) /*!< in: TRUE=check charsets
|
||||
compatibility */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
const char** col_names, /*!< in: column names, or NULL
|
||||
to use table->col_names */
|
||||
bool check_recursive,/*!< in: Whether to check
|
||||
recursive load of tables
|
||||
chained by FK */
|
||||
bool check_charsets, /*!< in: whether to check
|
||||
charset compatibility */
|
||||
dict_err_ignore_t ignore_err) /*!< in: error to be ignored */
|
||||
__attribute__((nonnull(1), warn_unused_result));
|
||||
/********************************************************************//**
|
||||
Prints to the standard output information on all tables found in the data
|
||||
dictionary system table. */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
@ -226,7 +226,7 @@ This could result in rescursive calls and out of stack error eventually.
|
|||
DICT_FK_MAX_RECURSIVE_LOAD defines the maximum number of recursive loads,
|
||||
when exceeded, the child table will not be loaded. It will be loaded when
|
||||
the foreign constraint check needs to be run. */
|
||||
#define DICT_FK_MAX_RECURSIVE_LOAD 255
|
||||
#define DICT_FK_MAX_RECURSIVE_LOAD 20
|
||||
|
||||
/** Similarly, when tables are chained together with foreign key constraints
|
||||
with on cascading delete/update clause, delete from parent table could
|
||||
|
|
@ -916,7 +916,9 @@ struct dict_table_t{
|
|||
the background stats thread will detect this
|
||||
and will eventually quit sooner */
|
||||
byte stats_bg_flag;
|
||||
/*!< see BG_STAT_* above */
|
||||
/*!< see BG_STAT_* above.
|
||||
Writes are covered by dict_sys->mutex.
|
||||
Dirty reads are possible. */
|
||||
/* @} */
|
||||
/*----------------------*/
|
||||
/**!< The following fields are used by the
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2010, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2010, 2013, 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
|
||||
|
|
@ -52,7 +52,9 @@ UNIV_INLINE
|
|||
dict_table_t*
|
||||
dict_table_open_on_id_low(
|
||||
/*=====================*/
|
||||
table_id_t table_id); /*!< in: table id */
|
||||
table_id_t table_id, /*!< in: table id */
|
||||
dict_err_ignore_t ignore_err); /*!< in: errors to ignore
|
||||
when loading the table */
|
||||
|
||||
#ifndef UNIV_NONINL
|
||||
#include "dict0priv.ic"
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2010, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2010, 2013, 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
|
||||
|
|
@ -73,7 +73,9 @@ UNIV_INLINE
|
|||
dict_table_t*
|
||||
dict_table_open_on_id_low(
|
||||
/*======================*/
|
||||
table_id_t table_id) /*!< in: table id */
|
||||
table_id_t table_id, /*!< in: table id */
|
||||
dict_err_ignore_t ignore_err) /*!< in: errors to ignore
|
||||
when loading the table */
|
||||
{
|
||||
dict_table_t* table;
|
||||
ulint fold;
|
||||
|
|
@ -87,7 +89,7 @@ dict_table_open_on_id_low(
|
|||
dict_table_t*, table, ut_ad(table->cached),
|
||||
table->id == table_id);
|
||||
if (table == NULL) {
|
||||
table = dict_load_table_on_id(table_id);
|
||||
table = dict_load_table_on_id(table_id, ignore_err);
|
||||
}
|
||||
|
||||
ut_ad(!table || table->cached);
|
||||
|
|
|
|||
|
|
@ -31,8 +31,7 @@ Created Jan 23, 2012 Vasil Dimov
|
|||
/*********************************************************************//**
|
||||
Set the persistent statistics flag for a given table. This is set only
|
||||
in the in-memory table object and is not saved on disk. It will be read
|
||||
from the .frm file upon first open from MySQL after a server restart.
|
||||
dict_stats_set_persistent() @{ */
|
||||
from the .frm file upon first open from MySQL after a server restart. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_set_persistent(
|
||||
|
|
@ -61,11 +60,9 @@ dict_stats_set_persistent(
|
|||
/* we rely on this assignment to be atomic */
|
||||
table->stat_persistent = stat_persistent;
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Check whether persistent statistics is enabled for a given table.
|
||||
dict_stats_is_persistent_enabled() @{
|
||||
@return TRUE if enabled, FALSE otherwise */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
|
|
@ -100,14 +97,12 @@ dict_stats_is_persistent_enabled(
|
|||
return(srv_stats_persistent);
|
||||
}
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Set the auto recalc flag for a given table (only honored for a persistent
|
||||
stats enabled table). The flag is set only in the in-memory table object
|
||||
and is not saved in InnoDB files. It will be read from the .frm file upon
|
||||
first open from MySQL after a server restart.
|
||||
dict_stats_auto_recalc_set() @{ */
|
||||
first open from MySQL after a server restart. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_auto_recalc_set(
|
||||
|
|
@ -131,11 +126,9 @@ dict_stats_auto_recalc_set(
|
|||
/* we rely on this assignment to be atomic */
|
||||
table->stats_auto_recalc = stats_auto_recalc;
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Check whether auto recalc is enabled for a given table.
|
||||
dict_stats_auto_recalc_is_enabled() @{
|
||||
@return TRUE if enabled, FALSE otherwise */
|
||||
UNIV_INLINE
|
||||
ibool
|
||||
|
|
@ -155,11 +148,9 @@ dict_stats_auto_recalc_is_enabled(
|
|||
return(srv_stats_auto_recalc);
|
||||
}
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Initialize table's stats for the first time when opening a table.
|
||||
dict_stats_init() @{ */
|
||||
Initialize table's stats for the first time when opening a table. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_init(
|
||||
|
|
@ -182,12 +173,10 @@ dict_stats_init(
|
|||
|
||||
dict_stats_update(table, opt);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/*********************************************************************//**
|
||||
Deinitialize table's stats after the last close of the table. This is
|
||||
used to detect "FLUSH TABLE" and refresh the stats upon next open.
|
||||
dict_stats_deinit() @{ */
|
||||
used to detect "FLUSH TABLE" and refresh the stats upon next open. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dict_stats_deinit(
|
||||
|
|
@ -245,6 +234,3 @@ dict_stats_deinit(
|
|||
|
||||
dict_table_stats_unlock(table, RW_X_LATCH);
|
||||
}
|
||||
/* @} */
|
||||
|
||||
/* vim: set foldmethod=marker foldmarker=@{,@}: */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, 2013, 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
|
||||
|
|
@ -40,14 +40,12 @@ Add a table to the recalc pool, which is processed by the
|
|||
background stats gathering thread. Only the table id is added to the
|
||||
list, so the table can be closed after being enqueued and it will be
|
||||
opened when needed. If the table does not exist later (has been DROPped),
|
||||
then it will be removed from the pool and skipped.
|
||||
dict_stats_recalc_pool_add() @{ */
|
||||
then it will be removed from the pool and skipped. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_recalc_pool_add(
|
||||
/*=======================*/
|
||||
const dict_table_t* table); /*!< in: table to add */
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Delete a given table from the auto recalc pool.
|
||||
|
|
@ -57,53 +55,63 @@ void
|
|||
dict_stats_recalc_pool_del(
|
||||
/*=======================*/
|
||||
const dict_table_t* table); /*!< in: table to remove */
|
||||
/* @} */
|
||||
|
||||
/** Yield the data dictionary latch when waiting
|
||||
for the background thread to stop accessing a table.
|
||||
@param trx transaction holding the data dictionary locks */
|
||||
#define DICT_STATS_BG_YIELD(trx) do { \
|
||||
row_mysql_unlock_data_dictionary(trx); \
|
||||
os_thread_sleep(250000); \
|
||||
row_mysql_lock_data_dictionary(trx); \
|
||||
} while (0)
|
||||
|
||||
/*****************************************************************//**
|
||||
Wait until background stats thread has stopped using the specified table(s).
|
||||
Request the background collection of statistics to stop for a table.
|
||||
@retval true when no background process is active
|
||||
@retval false when it is not safe to modify the table definition */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
dict_stats_stop_bg(
|
||||
/*===============*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
__attribute__((warn_unused_result));
|
||||
|
||||
/*****************************************************************//**
|
||||
Wait until background stats thread has stopped using the specified table.
|
||||
The caller must have locked the data dictionary using
|
||||
row_mysql_lock_data_dictionary() and this function may unlock it temporarily
|
||||
and restore the lock before it exits.
|
||||
The background stats thead is guaranteed not to start using the specified
|
||||
tables after this function returns and before the caller unlocks the data
|
||||
The background stats thread is guaranteed not to start using the specified
|
||||
table after this function returns and before the caller unlocks the data
|
||||
dictionary because it sets the BG_STAT_IN_PROGRESS bit in table->stats_bg_flag
|
||||
under dict_sys->mutex.
|
||||
dict_stats_wait_bg_to_stop_using_table() @{ */
|
||||
under dict_sys->mutex. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_wait_bg_to_stop_using_tables(
|
||||
/*====================================*/
|
||||
dict_table_t* table1, /*!< in/out: table1 */
|
||||
dict_table_t* table2, /*!< in/out: table2, could be NULL */
|
||||
dict_stats_wait_bg_to_stop_using_table(
|
||||
/*===================================*/
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
trx_t* trx); /*!< in/out: transaction to use for
|
||||
unlocking/locking the data dict */
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Initialize global variables needed for the operation of dict_stats_thread().
|
||||
Must be called before dict_stats_thread() is started.
|
||||
dict_stats_thread_init() @{ */
|
||||
Must be called before dict_stats_thread() is started. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_thread_init();
|
||||
/*====================*/
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
Free resources allocated by dict_stats_thread_init(), must be called
|
||||
after dict_stats_thread() has exited.
|
||||
dict_stats_thread_deinit() @{ */
|
||||
after dict_stats_thread() has exited. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_stats_thread_deinit();
|
||||
/*======================*/
|
||||
/* @} */
|
||||
|
||||
/*****************************************************************//**
|
||||
This is the thread for background stats gathering. It pops tables, from
|
||||
the auto recalc list and proceeds them, eventually recalculating their
|
||||
statistics.
|
||||
dict_stats_thread() @{
|
||||
@return this function does not return, it calls os_thread_exit() */
|
||||
extern "C" UNIV_INTERN
|
||||
os_thread_ret_t
|
||||
|
|
@ -111,6 +119,9 @@ DECLARE_THREAD(dict_stats_thread)(
|
|||
/*==============================*/
|
||||
void* arg); /*!< in: a dummy parameter
|
||||
required by os_thread_create */
|
||||
/* @} */
|
||||
|
||||
# ifndef UNIV_NONINL
|
||||
# include "dict0stats_bg.ic"
|
||||
# endif
|
||||
|
||||
#endif /* dict0stats_bg_h */
|
||||
|
|
|
|||
45
storage/innobase/include/dict0stats_bg.ic
Normal file
45
storage/innobase/include/dict0stats_bg.ic
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2012, 2013, 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
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/**************************************************//**
|
||||
@file include/dict0stats_bg.ic
|
||||
Code used for background table and index stats gathering.
|
||||
|
||||
Created Feb 8, 2013 Marko Makela
|
||||
*******************************************************/
|
||||
|
||||
/*****************************************************************//**
|
||||
Request the background collection of statistics to stop for a table.
|
||||
@retval true when no background process is active
|
||||
@retval false when it is not safe to modify the table definition */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
dict_stats_stop_bg(
|
||||
/*===============*/
|
||||
dict_table_t* table) /*!< in/out: table */
|
||||
{
|
||||
ut_ad(!srv_read_only_mode);
|
||||
ut_ad(mutex_own(&dict_sys->mutex));
|
||||
|
||||
if (!(table->stats_bg_flag & BG_STAT_IN_PROGRESS)) {
|
||||
return(true);
|
||||
}
|
||||
|
||||
table->stats_bg_flag |= BG_STAT_SHOULD_QUIT;
|
||||
return(false);
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -57,6 +57,14 @@ enum dict_err_ignore_t {
|
|||
DICT_ERR_IGNORE_INDEX_ROOT = 1, /*!< ignore error if index root
|
||||
page is FIL_NULL or incorrect value */
|
||||
DICT_ERR_IGNORE_CORRUPT = 2, /*!< skip corrupted indexes */
|
||||
DICT_ERR_IGNORE_FK_NOKEY = 4, /*!< ignore error if any foreign
|
||||
key is missing */
|
||||
DICT_ERR_IGNORE_RECOVER_LOCK = 8,
|
||||
/*!< Used when recovering table locks
|
||||
for resurrected transactions.
|
||||
Silently load a missing
|
||||
tablespace, and do not load
|
||||
incomplete index definitions. */
|
||||
DICT_ERR_IGNORE_ALL = 0xFFFF /*!< ignore all errors */
|
||||
};
|
||||
|
||||
|
|
@ -67,4 +75,11 @@ enum ib_quiesce_t {
|
|||
QUIESCE_COMPLETE /*!< All done */
|
||||
};
|
||||
|
||||
/** Prefix for tmp tables, adopted from sql/table.h */
|
||||
#define tmp_file_prefix "#sql"
|
||||
#define tmp_file_prefix_length 4
|
||||
|
||||
#define TEMP_TABLE_PREFIX "#sql"
|
||||
#define TEMP_TABLE_PATH_PREFIX "/" TEMP_TABLE_PREFIX
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -46,15 +46,17 @@ UNIV_INLINE
|
|||
dyn_array_t*
|
||||
dyn_array_create(
|
||||
/*=============*/
|
||||
dyn_array_t* arr); /*!< in: pointer to a memory buffer of
|
||||
dyn_array_t* arr) /*!< in/out memory buffer of
|
||||
size sizeof(dyn_array_t) */
|
||||
__attribute__((nonnull));
|
||||
/************************************************************//**
|
||||
Frees a dynamic array. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dyn_array_free(
|
||||
/*===========*/
|
||||
dyn_array_t* arr); /*!< in: dyn array */
|
||||
dyn_array_t* arr) /*!< in,own: dyn array */
|
||||
__attribute__((nonnull));
|
||||
/*********************************************************************//**
|
||||
Makes room on top of a dyn array and returns a pointer to a buffer in it.
|
||||
After copying the elements, the caller must close the buffer using
|
||||
|
|
@ -65,8 +67,9 @@ byte*
|
|||
dyn_array_open(
|
||||
/*===========*/
|
||||
dyn_array_t* arr, /*!< in: dynamic array */
|
||||
ulint size); /*!< in: size in bytes of the buffer; MUST be
|
||||
ulint size) /*!< in: size in bytes of the buffer; MUST be
|
||||
smaller than DYN_ARRAY_DATA_SIZE! */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/*********************************************************************//**
|
||||
Closes the buffer returned by dyn_array_open. */
|
||||
UNIV_INLINE
|
||||
|
|
@ -74,7 +77,8 @@ void
|
|||
dyn_array_close(
|
||||
/*============*/
|
||||
dyn_array_t* arr, /*!< in: dynamic array */
|
||||
byte* ptr); /*!< in: buffer space from ptr up was not used */
|
||||
const byte* ptr) /*!< in: end of used space */
|
||||
__attribute__((nonnull));
|
||||
/*********************************************************************//**
|
||||
Makes room on top of a dyn array and returns a pointer to
|
||||
the added element. The caller must copy the element to
|
||||
|
|
@ -84,8 +88,9 @@ UNIV_INLINE
|
|||
void*
|
||||
dyn_array_push(
|
||||
/*===========*/
|
||||
dyn_array_t* arr, /*!< in: dynamic array */
|
||||
ulint size); /*!< in: size in bytes of the element */
|
||||
dyn_array_t* arr, /*!< in/out: dynamic array */
|
||||
ulint size) /*!< in: size in bytes of the element */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/************************************************************//**
|
||||
Returns pointer to an element in dyn array.
|
||||
@return pointer to element */
|
||||
|
|
@ -93,9 +98,10 @@ UNIV_INLINE
|
|||
void*
|
||||
dyn_array_get_element(
|
||||
/*==================*/
|
||||
dyn_array_t* arr, /*!< in: dyn array */
|
||||
ulint pos); /*!< in: position of element as bytes
|
||||
from array start */
|
||||
const dyn_array_t* arr, /*!< in: dyn array */
|
||||
ulint pos) /*!< in: position of element
|
||||
in bytes from array start */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/************************************************************//**
|
||||
Returns the size of stored data in a dyn array.
|
||||
@return data size in bytes */
|
||||
|
|
@ -103,30 +109,33 @@ UNIV_INLINE
|
|||
ulint
|
||||
dyn_array_get_data_size(
|
||||
/*====================*/
|
||||
dyn_array_t* arr); /*!< in: dyn array */
|
||||
const dyn_array_t* arr) /*!< in: dyn array */
|
||||
__attribute__((nonnull, warn_unused_result, pure));
|
||||
/************************************************************//**
|
||||
Gets the first block in a dyn array. */
|
||||
UNIV_INLINE
|
||||
dyn_block_t*
|
||||
dyn_array_get_first_block(
|
||||
/*======================*/
|
||||
dyn_array_t* arr); /*!< in: dyn array */
|
||||
Gets the first block in a dyn array.
|
||||
@param arr dyn array
|
||||
@return first block */
|
||||
#define dyn_array_get_first_block(arr) (arr)
|
||||
/************************************************************//**
|
||||
Gets the last block in a dyn array. */
|
||||
UNIV_INLINE
|
||||
dyn_block_t*
|
||||
dyn_array_get_last_block(
|
||||
/*=====================*/
|
||||
dyn_array_t* arr); /*!< in: dyn array */
|
||||
Gets the last block in a dyn array.
|
||||
@param arr dyn array
|
||||
@return last block */
|
||||
#define dyn_array_get_last_block(arr) \
|
||||
((arr)->heap ? UT_LIST_GET_LAST((arr)->base) : (arr))
|
||||
/********************************************************************//**
|
||||
Gets the next block in a dyn array.
|
||||
@param arr dyn array
|
||||
@param block dyn array block
|
||||
@return pointer to next, NULL if end of list */
|
||||
UNIV_INLINE
|
||||
dyn_block_t*
|
||||
dyn_array_get_next_block(
|
||||
/*=====================*/
|
||||
dyn_array_t* arr, /*!< in: dyn array */
|
||||
dyn_block_t* block); /*!< in: dyn array block */
|
||||
#define dyn_array_get_next_block(arr, block) \
|
||||
((arr)->heap ? UT_LIST_GET_NEXT(list, block) : NULL)
|
||||
/********************************************************************//**
|
||||
Gets the previous block in a dyn array.
|
||||
@param arr dyn array
|
||||
@param block dyn array block
|
||||
@return pointer to previous, NULL if end of list */
|
||||
#define dyn_array_get_prev_block(arr, block) \
|
||||
((arr)->heap ? UT_LIST_GET_PREV(list, block) : NULL)
|
||||
/********************************************************************//**
|
||||
Gets the number of used bytes in a dyn array block.
|
||||
@return number of bytes used */
|
||||
|
|
@ -134,7 +143,8 @@ UNIV_INLINE
|
|||
ulint
|
||||
dyn_block_get_used(
|
||||
/*===============*/
|
||||
dyn_block_t* block); /*!< in: dyn array block */
|
||||
const dyn_block_t* block) /*!< in: dyn array block */
|
||||
__attribute__((nonnull, warn_unused_result, pure));
|
||||
/********************************************************************//**
|
||||
Gets pointer to the start of data in a dyn array block.
|
||||
@return pointer to data */
|
||||
|
|
@ -142,16 +152,18 @@ UNIV_INLINE
|
|||
byte*
|
||||
dyn_block_get_data(
|
||||
/*===============*/
|
||||
dyn_block_t* block); /*!< in: dyn array block */
|
||||
const dyn_block_t* block) /*!< in: dyn array block */
|
||||
__attribute__((nonnull, warn_unused_result, pure));
|
||||
/********************************************************//**
|
||||
Pushes n bytes to a dyn array. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
dyn_push_string(
|
||||
/*============*/
|
||||
dyn_array_t* arr, /*!< in: dyn array */
|
||||
dyn_array_t* arr, /*!< in/out: dyn array */
|
||||
const byte* str, /*!< in: string to write */
|
||||
ulint len); /*!< in: string length */
|
||||
ulint len) /*!< in: string length */
|
||||
__attribute__((nonnull));
|
||||
|
||||
/*#################################################################*/
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -35,56 +35,8 @@ UNIV_INTERN
|
|||
dyn_block_t*
|
||||
dyn_array_add_block(
|
||||
/*================*/
|
||||
dyn_array_t* arr); /*!< in: dyn array */
|
||||
|
||||
|
||||
/************************************************************//**
|
||||
Gets the first block in a dyn array. */
|
||||
UNIV_INLINE
|
||||
dyn_block_t*
|
||||
dyn_array_get_first_block(
|
||||
/*======================*/
|
||||
dyn_array_t* arr) /*!< in: dyn array */
|
||||
{
|
||||
return(arr);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
Gets the last block in a dyn array. */
|
||||
UNIV_INLINE
|
||||
dyn_block_t*
|
||||
dyn_array_get_last_block(
|
||||
/*=====================*/
|
||||
dyn_array_t* arr) /*!< in: dyn array */
|
||||
{
|
||||
if (arr->heap == NULL) {
|
||||
|
||||
return(arr);
|
||||
}
|
||||
|
||||
return(UT_LIST_GET_LAST(arr->base));
|
||||
}
|
||||
|
||||
/********************************************************************//**
|
||||
Gets the next block in a dyn array.
|
||||
@return pointer to next, NULL if end of list */
|
||||
UNIV_INLINE
|
||||
dyn_block_t*
|
||||
dyn_array_get_next_block(
|
||||
/*=====================*/
|
||||
dyn_array_t* arr, /*!< in: dyn array */
|
||||
dyn_block_t* block) /*!< in: dyn array block */
|
||||
{
|
||||
ut_ad(arr && block);
|
||||
|
||||
if (arr->heap == NULL) {
|
||||
ut_ad(arr == block);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
return(UT_LIST_GET_NEXT(list, block));
|
||||
}
|
||||
dyn_array_t* arr) /*!< in/out: dyn array */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
|
||||
/********************************************************************//**
|
||||
Gets the number of used bytes in a dyn array block.
|
||||
|
|
@ -93,7 +45,7 @@ UNIV_INLINE
|
|||
ulint
|
||||
dyn_block_get_used(
|
||||
/*===============*/
|
||||
dyn_block_t* block) /*!< in: dyn array block */
|
||||
const dyn_block_t* block) /*!< in: dyn array block */
|
||||
{
|
||||
ut_ad(block);
|
||||
|
||||
|
|
@ -107,11 +59,11 @@ UNIV_INLINE
|
|||
byte*
|
||||
dyn_block_get_data(
|
||||
/*===============*/
|
||||
dyn_block_t* block) /*!< in: dyn array block */
|
||||
const dyn_block_t* block) /*!< in: dyn array block */
|
||||
{
|
||||
ut_ad(block);
|
||||
|
||||
return(block->data);
|
||||
return(const_cast<byte*>(block->data));
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
|
@ -121,7 +73,7 @@ UNIV_INLINE
|
|||
dyn_array_t*
|
||||
dyn_array_create(
|
||||
/*=============*/
|
||||
dyn_array_t* arr) /*!< in: pointer to a memory buffer of
|
||||
dyn_array_t* arr) /*!< in/out: memory buffer of
|
||||
size sizeof(dyn_array_t) */
|
||||
{
|
||||
ut_ad(arr);
|
||||
|
|
@ -132,10 +84,9 @@ dyn_array_create(
|
|||
arr->heap = NULL;
|
||||
arr->used = 0;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
arr->buf_end = 0;
|
||||
arr->magic_n = DYN_BLOCK_MAGIC_N;
|
||||
#endif
|
||||
ut_d(arr->buf_end = 0);
|
||||
ut_d(arr->magic_n = DYN_BLOCK_MAGIC_N);
|
||||
|
||||
return(arr);
|
||||
}
|
||||
|
||||
|
|
@ -151,9 +102,7 @@ dyn_array_free(
|
|||
mem_heap_free(arr->heap);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
arr->magic_n = 0;
|
||||
#endif
|
||||
ut_d(arr->magic_n = 0);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
|
@ -164,7 +113,7 @@ UNIV_INLINE
|
|||
void*
|
||||
dyn_array_push(
|
||||
/*===========*/
|
||||
dyn_array_t* arr, /*!< in: dynamic array */
|
||||
dyn_array_t* arr, /*!< in/out: dynamic array */
|
||||
ulint size) /*!< in: size in bytes of the element */
|
||||
{
|
||||
dyn_block_t* block;
|
||||
|
|
@ -176,24 +125,23 @@ dyn_array_push(
|
|||
ut_ad(size);
|
||||
|
||||
block = arr;
|
||||
used = block->used;
|
||||
|
||||
if (used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
if (block->used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
/* Get the last array block */
|
||||
|
||||
block = dyn_array_get_last_block(arr);
|
||||
used = block->used;
|
||||
|
||||
if (used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
if (block->used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
block = dyn_array_add_block(arr);
|
||||
}
|
||||
}
|
||||
|
||||
used = block->used;
|
||||
}
|
||||
}
|
||||
|
||||
block->used = used + size;
|
||||
ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
|
||||
|
||||
return((block->data) + used);
|
||||
return(block->data + used);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
|
@ -210,7 +158,6 @@ dyn_array_open(
|
|||
smaller than DYN_ARRAY_DATA_SIZE! */
|
||||
{
|
||||
dyn_block_t* block;
|
||||
ulint used;
|
||||
|
||||
ut_ad(arr);
|
||||
ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
|
||||
|
|
@ -218,28 +165,23 @@ dyn_array_open(
|
|||
ut_ad(size);
|
||||
|
||||
block = arr;
|
||||
used = block->used;
|
||||
|
||||
if (used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
if (block->used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
/* Get the last array block */
|
||||
|
||||
block = dyn_array_get_last_block(arr);
|
||||
used = block->used;
|
||||
|
||||
if (used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
if (block->used + size > DYN_ARRAY_DATA_SIZE) {
|
||||
block = dyn_array_add_block(arr);
|
||||
used = block->used;
|
||||
ut_a(size <= DYN_ARRAY_DATA_SIZE);
|
||||
}
|
||||
}
|
||||
|
||||
ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
|
||||
#ifdef UNIV_DEBUG
|
||||
ut_ad(arr->buf_end == 0);
|
||||
ut_d(arr->buf_end = block->used + size);
|
||||
|
||||
arr->buf_end = used + size;
|
||||
#endif
|
||||
return((block->data) + used);
|
||||
return(block->data + block->used);
|
||||
}
|
||||
|
||||
/*********************************************************************//**
|
||||
|
|
@ -248,8 +190,8 @@ UNIV_INLINE
|
|||
void
|
||||
dyn_array_close(
|
||||
/*============*/
|
||||
dyn_array_t* arr, /*!< in: dynamic array */
|
||||
byte* ptr) /*!< in: buffer space from ptr up was not used */
|
||||
dyn_array_t* arr, /*!< in/out: dynamic array */
|
||||
const byte* ptr) /*!< in: end of used space */
|
||||
{
|
||||
dyn_block_t* block;
|
||||
|
||||
|
|
@ -264,9 +206,7 @@ dyn_array_close(
|
|||
|
||||
ut_ad(block->used <= DYN_ARRAY_DATA_SIZE);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
arr->buf_end = 0;
|
||||
#endif
|
||||
ut_d(arr->buf_end = 0);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
|
|
@ -276,12 +216,11 @@ UNIV_INLINE
|
|||
void*
|
||||
dyn_array_get_element(
|
||||
/*==================*/
|
||||
dyn_array_t* arr, /*!< in: dyn array */
|
||||
ulint pos) /*!< in: position of element as bytes
|
||||
from array start */
|
||||
const dyn_array_t* arr, /*!< in: dyn array */
|
||||
ulint pos) /*!< in: position of element
|
||||
in bytes from array start */
|
||||
{
|
||||
dyn_block_t* block;
|
||||
ulint used;
|
||||
const dyn_block_t* block;
|
||||
|
||||
ut_ad(arr);
|
||||
ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
|
||||
|
|
@ -290,21 +229,23 @@ dyn_array_get_element(
|
|||
block = dyn_array_get_first_block(arr);
|
||||
|
||||
if (arr->heap != NULL) {
|
||||
used = dyn_block_get_used(block);
|
||||
for (;;) {
|
||||
ulint used = dyn_block_get_used(block);
|
||||
|
||||
if (pos < used) {
|
||||
break;
|
||||
}
|
||||
|
||||
while (pos >= used) {
|
||||
pos -= used;
|
||||
block = UT_LIST_GET_NEXT(list, block);
|
||||
ut_ad(block);
|
||||
|
||||
used = dyn_block_get_used(block);
|
||||
}
|
||||
}
|
||||
|
||||
ut_ad(block);
|
||||
ut_ad(dyn_block_get_used(block) >= pos);
|
||||
|
||||
return(block->data + pos);
|
||||
return(const_cast<byte*>(block->data) + pos);
|
||||
}
|
||||
|
||||
/************************************************************//**
|
||||
|
|
@ -314,9 +255,9 @@ UNIV_INLINE
|
|||
ulint
|
||||
dyn_array_get_data_size(
|
||||
/*====================*/
|
||||
dyn_array_t* arr) /*!< in: dyn array */
|
||||
const dyn_array_t* arr) /*!< in: dyn array */
|
||||
{
|
||||
dyn_block_t* block;
|
||||
const dyn_block_t* block;
|
||||
ulint sum = 0;
|
||||
|
||||
ut_ad(arr);
|
||||
|
|
@ -344,7 +285,7 @@ UNIV_INLINE
|
|||
void
|
||||
dyn_push_string(
|
||||
/*============*/
|
||||
dyn_array_t* arr, /*!< in: dyn array */
|
||||
dyn_array_t* arr, /*!< in/out: dyn array */
|
||||
const byte* str, /*!< in: string to write */
|
||||
ulint len) /*!< in: string length */
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, 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
|
||||
|
|
@ -360,9 +360,11 @@ fil_write_flushed_lsn_to_data_files(
|
|||
ulint arch_log_no); /*!< in: latest archived log file number */
|
||||
/*******************************************************************//**
|
||||
Reads the flushed lsn, arch no, and tablespace flag fields from a data
|
||||
file at database startup. */
|
||||
file at database startup.
|
||||
@retval NULL on success, or if innodb_force_recovery is set
|
||||
@return pointer to an error message string */
|
||||
UNIV_INTERN
|
||||
void
|
||||
const char*
|
||||
fil_read_first_page(
|
||||
/*================*/
|
||||
os_file_t data_file, /*!< in: open data file */
|
||||
|
|
@ -379,8 +381,9 @@ fil_read_first_page(
|
|||
#endif /* UNIV_LOG_ARCHIVE */
|
||||
lsn_t* min_flushed_lsn, /*!< out: min of flushed
|
||||
lsn values in data files */
|
||||
lsn_t* max_flushed_lsn); /*!< out: max of flushed
|
||||
lsn_t* max_flushed_lsn) /*!< out: max of flushed
|
||||
lsn values in data files */
|
||||
__attribute__((warn_unused_result));
|
||||
/*******************************************************************//**
|
||||
Increments the count of pending operation, if space is not being deleted.
|
||||
@return TRUE if being deleted, and operation should be skipped */
|
||||
|
|
@ -728,7 +731,7 @@ fil_io(
|
|||
because i/os are not actually handled until
|
||||
all have been posted: use with great
|
||||
caution! */
|
||||
ibool sync, /*!< in: TRUE if synchronous aio is desired */
|
||||
bool sync, /*!< in: true if synchronous aio is desired */
|
||||
ulint space_id, /*!< in: space id */
|
||||
ulint zip_size, /*!< in: compressed page size in bytes;
|
||||
0 for uncompressed pages */
|
||||
|
|
@ -977,8 +980,10 @@ fil_mtr_rename_log(
|
|||
ulint new_space_id, /*!< in: tablespace id of the new
|
||||
table */
|
||||
const char* new_name, /*!< in: new table name */
|
||||
const char* tmp_name); /*!< in: temp table name used while
|
||||
const char* tmp_name, /*!< in: temp table name used while
|
||||
swapping */
|
||||
mtr_t* mtr) /*!< in/out: mini-transaction */
|
||||
__attribute__((nonnull));
|
||||
|
||||
#endif /* !UNIV_INNOCHECKSUM */
|
||||
#endif /* fil0fil_h */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2007, 2013, 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
|
||||
|
|
@ -27,6 +27,7 @@ Created 2007/03/16/03 Sunny Bains
|
|||
#define INNOBASE_FST0AST_H
|
||||
|
||||
#include "mem0mem.h"
|
||||
#include "ha_prototypes.h"
|
||||
|
||||
/* The type of AST Node */
|
||||
enum fts_ast_type_t {
|
||||
|
|
@ -59,11 +60,16 @@ enum fts_ast_oper_t {
|
|||
word*/
|
||||
|
||||
FTS_DISTANCE, /*!< Proximity distance */
|
||||
FTS_IGNORE_SKIP /*!< Transient node operator
|
||||
FTS_IGNORE_SKIP, /*!< Transient node operator
|
||||
signifies that this is a
|
||||
FTS_IGNORE node, and ignored in
|
||||
the first pass of
|
||||
fts_ast_visit() */
|
||||
FTS_EXIST_SKIP /*!< Transient node operator
|
||||
signifies that this ia a
|
||||
FTS_EXIST node, and ignored in
|
||||
the first pass of
|
||||
fts_ast_visit() */
|
||||
};
|
||||
|
||||
/* Data types used by the FTS parser */
|
||||
|
|
@ -71,7 +77,7 @@ struct fts_lexer_t;
|
|||
struct fts_ast_node_t;
|
||||
struct fts_ast_state_t;
|
||||
|
||||
typedef ulint (*fts_ast_callback)(fts_ast_oper_t, fts_ast_node_t*, void*);
|
||||
typedef dberr_t (*fts_ast_callback)(fts_ast_oper_t, fts_ast_node_t*, void*);
|
||||
|
||||
/********************************************************************
|
||||
Parse the string using the lexer setup within state.*/
|
||||
|
|
@ -268,6 +274,8 @@ struct fts_ast_state_t {
|
|||
fts_ast_list_t list; /*!< List of nodes allocated */
|
||||
|
||||
fts_lexer_t* lexer; /*!< Lexer callback + arg */
|
||||
CHARSET_INFO* charset; /*!< charset used for
|
||||
tokenization */
|
||||
};
|
||||
|
||||
#endif /* INNOBASE_FSTS0AST_H */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2011, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2011, 2013, 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
|
||||
|
|
@ -87,6 +87,7 @@ those defined in mysql file ft_global.h */
|
|||
#define FTS_EXPAND 4
|
||||
#define FTS_PROXIMITY 8
|
||||
#define FTS_PHRASE 16
|
||||
#define FTS_OPT_RANKING 32
|
||||
|
||||
#define FTS_INDEX_TABLE_IND_NAME "FTS_INDEX_TABLE_IND"
|
||||
|
||||
|
|
@ -240,9 +241,10 @@ struct fts_ranking_t {
|
|||
|
||||
fts_rank_t rank; /*!< Rank is between 0 .. 1 */
|
||||
|
||||
ib_rbt_t* words; /*!< RB Tree of type byte*, this
|
||||
contains the words that were queried
|
||||
byte* words; /*!< this contains the words
|
||||
that were queried
|
||||
and found in this document */
|
||||
ulint words_len; /*!< words len */
|
||||
};
|
||||
|
||||
/** Query result. */
|
||||
|
|
@ -345,14 +347,27 @@ extern const char* fts_default_stopword[];
|
|||
/** Variable specifying the maximum FTS cache size for each table */
|
||||
extern ulong fts_max_cache_size;
|
||||
|
||||
/** Variable specifying the total memory allocated for FTS cache */
|
||||
extern ulong fts_max_total_cache_size;
|
||||
|
||||
/** Variable specifying the FTS result cache limit for each query */
|
||||
extern ulong fts_result_cache_limit;
|
||||
|
||||
/** Variable specifying the maximum FTS max token size */
|
||||
extern ulong fts_max_token_size;
|
||||
|
||||
/** Variable specifying the minimum FTS max token size */
|
||||
extern ulong fts_min_token_size;
|
||||
|
||||
/** Whether the total memory used for FTS cache is exhausted, and we will
|
||||
need a sync to free some memory */
|
||||
extern bool fts_need_sync;
|
||||
|
||||
/** Maximum possible Fulltext word length */
|
||||
#define FTS_MAX_WORD_LEN 3 * HA_FT_MAXCHARLEN
|
||||
#define FTS_MAX_WORD_LEN HA_FT_MAXBYTELEN
|
||||
|
||||
/** Maximum possible Fulltext word length (in characters) */
|
||||
#define FTS_MAX_WORD_LEN_IN_CHAR HA_FT_MAXCHARLEN
|
||||
|
||||
/** Variable specifying the table that has Fulltext index to display its
|
||||
content through information schema table */
|
||||
|
|
@ -844,7 +859,7 @@ fts_index_get_charset(
|
|||
dict_index_t* index); /*!< in: FTS index */
|
||||
|
||||
/*********************************************************************//**
|
||||
Get the initial Doc ID by consulting the ADDED and the CONFIG table
|
||||
Get the initial Doc ID by consulting the CONFIG table
|
||||
@return initial Doc ID */
|
||||
UNIV_INTERN
|
||||
doc_id_t
|
||||
|
|
@ -894,8 +909,8 @@ ulint
|
|||
innobase_mysql_fts_get_token(
|
||||
/*=========================*/
|
||||
CHARSET_INFO* charset, /*!< in: Character set */
|
||||
byte* start, /*!< in: start of text */
|
||||
byte* end, /*!< in: one character past
|
||||
const byte* start, /*!< in: start of text */
|
||||
const byte* end, /*!< in: one character past
|
||||
end of text */
|
||||
fts_string_t* token, /*!< out: token's text */
|
||||
ulint* offset); /*!< out: offset to token,
|
||||
|
|
@ -923,9 +938,9 @@ fts_get_max_doc_id(
|
|||
/******************************************************************//**
|
||||
Check whether user supplied stopword table exists and is of
|
||||
the right format.
|
||||
@return TRUE if the table qualifies */
|
||||
@return the stopword column charset if qualifies */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
CHARSET_INFO*
|
||||
fts_valid_stopword_table(
|
||||
/*=====================*/
|
||||
const char* stopword_table_name); /*!< in: Stopword table
|
||||
|
|
@ -970,9 +985,11 @@ fts_table_fetch_doc_ids(
|
|||
fts_doc_ids_t* doc_ids); /*!< in: For collecting
|
||||
doc ids */
|
||||
/****************************************************************//**
|
||||
This function loads the documents in "ADDED" table into FTS cache,
|
||||
it also loads the stopword info into the FTS cache.
|
||||
@return DB_SUCCESS if all OK */
|
||||
This function brings FTS index in sync when FTS index is first
|
||||
used. There are documents that have not yet sync-ed to auxiliary
|
||||
tables from last server abnormally shutdown, we will need to bring
|
||||
such document into FTS cache before any further operations
|
||||
@return TRUE if all OK */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
fts_init_index(
|
||||
|
|
@ -1001,6 +1018,17 @@ fts_drop_index(
|
|||
trx_t* trx) /*!< in: Transaction for the drop */
|
||||
__attribute__((nonnull));
|
||||
|
||||
/****************************************************************//**
|
||||
Rename auxiliary tables for all fts index for a table
|
||||
@return DB_SUCCESS or error code */
|
||||
|
||||
dberr_t
|
||||
fts_rename_aux_tables(
|
||||
/*==================*/
|
||||
dict_table_t* table, /*!< in: user Table */
|
||||
const char* new_name, /*!< in: new table name */
|
||||
trx_t* trx); /*!< in: transaction */
|
||||
|
||||
/*******************************************************************//**
|
||||
Check indexes in the fts->indexes is also present in index cache and
|
||||
table->indexes list
|
||||
|
|
|
|||
|
|
@ -1,10 +1,8 @@
|
|||
/* A Bison parser, made by GNU Bison 2.5. */
|
||||
|
||||
/* A Bison parser, made by GNU Bison 2.4.1. */
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
/* Skeleton interface for Bison's Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006
|
||||
Free Software Foundation, Inc.
|
||||
Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
|
||||
|
||||
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
|
||||
|
|
@ -52,8 +50,8 @@
|
|||
typedef union YYSTYPE
|
||||
{
|
||||
|
||||
/* Line 1676 of yacc.c */
|
||||
#line 36 "fts0pars.y"
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 61 "fts0pars.y"
|
||||
|
||||
int oper;
|
||||
char* token;
|
||||
|
|
@ -61,8 +59,8 @@ typedef union YYSTYPE
|
|||
|
||||
|
||||
|
||||
/* Line 1676 of yacc.c */
|
||||
#line 66 "fts0pars.h"
|
||||
/* Line 2068 of yacc.c */
|
||||
#line 64 "fts0pars.hh"
|
||||
} YYSTYPE;
|
||||
# define YYSTYPE_IS_TRIVIAL 1
|
||||
# define yystype YYSTYPE /* obsolescent; will be withdrawn */
|
||||
|
|
|
|||
|
|
@ -47,7 +47,8 @@ fts_utf8_string_dup(
|
|||
const fts_string_t* src, /*!< in: src string */
|
||||
mem_heap_t* heap) /*!< in: heap to use */
|
||||
{
|
||||
dst->f_str = (byte*) mem_heap_dup(heap, src->f_str, src->f_len + 1);
|
||||
dst->f_str = (byte*)mem_heap_alloc(heap, src->f_len + 1);
|
||||
memcpy(dst->f_str, src->f_str, src->f_len);
|
||||
|
||||
dst->f_len = src->f_len;
|
||||
dst->f_str[src->f_len] = 0;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2006, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2006, 2013, 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
|
||||
|
|
@ -396,8 +396,8 @@ ulint
|
|||
innobase_mysql_fts_get_token(
|
||||
/*=========================*/
|
||||
CHARSET_INFO* charset, /*!< in: Character set */
|
||||
byte* start, /*!< in: start of text */
|
||||
byte* end, /*!< in: one character past end of
|
||||
const byte* start, /*!< in: start of text */
|
||||
const byte* end, /*!< in: one character past end of
|
||||
text */
|
||||
fts_string_t* token, /*!< out: token's text */
|
||||
ulint* offset); /*!< out: offset to token,
|
||||
|
|
@ -595,4 +595,35 @@ innobase_convert_to_system_charset(
|
|||
ulint len, /* in: length of 'to', in bytes */
|
||||
uint* errors); /* out: error return */
|
||||
|
||||
/**********************************************************************
|
||||
Check if the length of the identifier exceeds the maximum allowed.
|
||||
The input to this function is an identifier in charset my_charset_filename.
|
||||
return true when length of identifier is too long. */
|
||||
UNIV_INTERN
|
||||
my_bool
|
||||
innobase_check_identifier_length(
|
||||
/*=============================*/
|
||||
const char* id); /* in: identifier to check. it must belong
|
||||
to charset my_charset_filename */
|
||||
|
||||
/**********************************************************************
|
||||
Converts an identifier from my_charset_filename to UTF-8 charset. */
|
||||
uint
|
||||
innobase_convert_to_system_charset(
|
||||
/*===============================*/
|
||||
char* to, /* out: converted identifier */
|
||||
const char* from, /* in: identifier to convert */
|
||||
ulint len, /* in: length of 'to', in bytes */
|
||||
uint* errors); /* out: error return */
|
||||
|
||||
/**********************************************************************
|
||||
Converts an identifier from my_charset_filename to UTF-8 charset. */
|
||||
uint
|
||||
innobase_convert_to_filename_charset(
|
||||
/*=================================*/
|
||||
char* to, /* out: converted identifier */
|
||||
const char* from, /* in: identifier to convert */
|
||||
ulint len); /* in: length of 'to', in bytes */
|
||||
|
||||
|
||||
#endif /* HA_INNODB_PROTOTYPES_H */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2005, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2005, 2013, 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
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2009, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1997, 2013, 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
|
||||
|
|
@ -413,9 +413,9 @@ ibuf_count_get(
|
|||
#endif
|
||||
/******************************************************************//**
|
||||
Looks if the insert buffer is empty.
|
||||
@return TRUE if empty */
|
||||
@return true if empty */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
bool
|
||||
ibuf_is_empty(void);
|
||||
/*===============*/
|
||||
/******************************************************************//**
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2009, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1997, 2013, 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
|
||||
|
|
@ -67,10 +67,10 @@ struct ibuf_t{
|
|||
ulint seg_size; /*!< allocated pages of the file
|
||||
segment containing ibuf header and
|
||||
tree */
|
||||
ibool empty; /*!< Protected by the page
|
||||
bool empty; /*!< Protected by the page
|
||||
latch of the root page of the
|
||||
insert buffer tree
|
||||
(FSP_IBUF_TREE_ROOT_PAGE_NO). TRUE
|
||||
(FSP_IBUF_TREE_ROOT_PAGE_NO). true
|
||||
if and only if the insert
|
||||
buffer tree is empty. */
|
||||
ulint free_list_len; /*!< length of the free list */
|
||||
|
|
@ -253,7 +253,15 @@ ibuf_index_page_calc_free_zip(
|
|||
ut_ad(zip_size == buf_block_get_zip_size(block));
|
||||
ut_ad(zip_size);
|
||||
|
||||
max_ins_size = page_get_max_insert_size_after_reorganize(
|
||||
/* Consider the maximum insert size on the uncompressed page
|
||||
without reorganizing the page. We must not assume anything
|
||||
about the compression ratio. If zip_max_ins > max_ins_size and
|
||||
there is 1/4 garbage on the page, recompression after the
|
||||
reorganize could fail, in theory. So, let us guarantee that
|
||||
merging a buffered insert to a compressed page will always
|
||||
succeed without reorganizing or recompressing the page, just
|
||||
by using the page modification log. */
|
||||
max_ins_size = page_get_max_insert_size(
|
||||
buf_block_get_frame(block), 1);
|
||||
|
||||
page_zip = buf_block_get_page_zip(block);
|
||||
|
|
@ -331,8 +339,8 @@ ibuf_update_free_bits_if_full(
|
|||
before = ibuf_index_page_calc_free_bits(0, max_ins_size);
|
||||
|
||||
if (max_ins_size >= increase) {
|
||||
#if ULINT32_UNDEFINED <= UNIV_PAGE_SIZE
|
||||
# error "ULINT32_UNDEFINED <= UNIV_PAGE_SIZE"
|
||||
#if ULINT32_UNDEFINED <= UNIV_PAGE_SIZE_MAX
|
||||
# error "ULINT32_UNDEFINED <= UNIV_PAGE_SIZE_MAX"
|
||||
#endif
|
||||
after = ibuf_index_page_calc_free_bits(0, max_ins_size
|
||||
- increase);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1996, 2013, 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
|
||||
|
|
@ -466,6 +466,14 @@ lock_table(
|
|||
enum lock_mode mode, /*!< in: lock mode */
|
||||
que_thr_t* thr) /*!< in: query thread */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
/*********************************************************************//**
|
||||
Creates a table IX lock object for a resurrected transaction. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
lock_table_ix_resurrect(
|
||||
/*====================*/
|
||||
dict_table_t* table, /*!< in/out: table */
|
||||
trx_t* trx); /*!< in/out: transaction */
|
||||
/*************************************************************//**
|
||||
Removes a granted record lock of a transaction from the queue and grants
|
||||
locks to other transactions waiting in the queue if they now are entitled
|
||||
|
|
@ -824,6 +832,19 @@ lock_trx_has_sys_table_locks(
|
|||
/*=========================*/
|
||||
const trx_t* trx) /*!< in: transaction to check */
|
||||
__attribute__((warn_unused_result));
|
||||
|
||||
/*******************************************************************//**
|
||||
Check if the transaction holds an exclusive lock on a record.
|
||||
@return whether the locks are held */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
lock_trx_has_rec_x_lock(
|
||||
/*====================*/
|
||||
const trx_t* trx, /*!< in: transaction to check */
|
||||
const dict_table_t* table, /*!< in: table to check */
|
||||
const buf_block_t* block, /*!< in: buffer block of the record */
|
||||
ulint heap_no)/*!< in: record heap number */
|
||||
__attribute__((nonnull, warn_unused_result));
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/** Lock modes and types */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All rights reserved.
|
||||
Copyright (c) 2009, Google Inc.
|
||||
|
||||
Portions of this file contain modifications contributed and copyrighted by
|
||||
|
|
@ -794,12 +794,14 @@ struct log_t{
|
|||
ulint max_buf_free; /*!< recommended maximum value of
|
||||
buf_free, after which the buffer is
|
||||
flushed */
|
||||
#ifdef UNIV_LOG_DEBUG
|
||||
ulint old_buf_free; /*!< value of buf free when log was
|
||||
last time opened; only in the debug
|
||||
version */
|
||||
ib_uint64_t old_lsn; /*!< value of lsn when log was
|
||||
last time opened; only in the
|
||||
debug version */
|
||||
#endif /* UNIV_LOG_DEBUG */
|
||||
ibool check_flush_or_checkpoint;
|
||||
/*!< this is set to TRUE when there may
|
||||
be need to flush the log buffer, or
|
||||
|
|
|
|||
|
|
@ -873,6 +873,8 @@ mach_read_ulint(
|
|||
default:
|
||||
ut_error;
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1995, 2013, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 2012, Facebook Inc.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
|
|
@ -299,14 +299,16 @@ mtr_x_lock_func(
|
|||
#endif /* !UNIV_HOTBACKUP */
|
||||
|
||||
/***************************************************//**
|
||||
Releases an object in the memo stack. */
|
||||
Releases an object in the memo stack.
|
||||
@return true if released */
|
||||
UNIV_INTERN
|
||||
void
|
||||
bool
|
||||
mtr_memo_release(
|
||||
/*=============*/
|
||||
mtr_t* mtr, /*!< in: mtr */
|
||||
mtr_t* mtr, /*!< in/out: mini-transaction */
|
||||
void* object, /*!< in: object */
|
||||
ulint type); /*!< in: object type: MTR_MEMO_S_LOCK, ... */
|
||||
ulint type) /*!< in: object type: MTR_MEMO_S_LOCK, ... */
|
||||
__attribute__((nonnull));
|
||||
#ifdef UNIV_DEBUG
|
||||
# ifndef UNIV_HOTBACKUP
|
||||
/**********************************************************//**
|
||||
|
|
@ -318,7 +320,8 @@ mtr_memo_contains(
|
|||
/*==============*/
|
||||
mtr_t* mtr, /*!< in: mtr */
|
||||
const void* object, /*!< in: object to search */
|
||||
ulint type); /*!< in: type of object */
|
||||
ulint type) /*!< in: type of object */
|
||||
__attribute__((warn_unused_result, nonnull));
|
||||
|
||||
/**********************************************************//**
|
||||
Checks if memo contains the given page.
|
||||
|
|
|
|||
|
|
@ -213,7 +213,9 @@ various file I/O operations with performance schema.
|
|||
1) register_pfs_file_open_begin() and register_pfs_file_open_end() are
|
||||
used to register file creation, opening, closing and renaming.
|
||||
2) register_pfs_file_io_begin() and register_pfs_file_io_end() are
|
||||
used to register actual file read, write and flush */
|
||||
used to register actual file read, write and flush
|
||||
3) register_pfs_file_close_begin() and register_pfs_file_close_end()
|
||||
are used to register file deletion operations*/
|
||||
# define register_pfs_file_open_begin(state, locker, key, op, name, \
|
||||
src_file, src_line) \
|
||||
do { \
|
||||
|
|
@ -233,6 +235,25 @@ do { \
|
|||
} \
|
||||
} while (0)
|
||||
|
||||
# define register_pfs_file_close_begin(state, locker, key, op, name, \
|
||||
src_file, src_line) \
|
||||
do { \
|
||||
locker = PSI_FILE_CALL(get_thread_file_name_locker)( \
|
||||
state, key, op, name, &locker); \
|
||||
if (UNIV_LIKELY(locker != NULL)) { \
|
||||
PSI_FILE_CALL(start_file_close_wait)( \
|
||||
locker, src_file, src_line); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# define register_pfs_file_close_end(locker, result) \
|
||||
do { \
|
||||
if (UNIV_LIKELY(locker != NULL)) { \
|
||||
PSI_FILE_CALL(end_file_close_wait)( \
|
||||
locker, result); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
# define register_pfs_file_io_begin(state, locker, file, count, op, \
|
||||
src_file, src_line) \
|
||||
do { \
|
||||
|
|
@ -306,6 +327,12 @@ The wrapper functions have the prefix of "innodb_". */
|
|||
|
||||
# define os_file_rename(key, oldpath, newpath) \
|
||||
pfs_os_file_rename_func(key, oldpath, newpath, __FILE__, __LINE__)
|
||||
|
||||
# define os_file_delete(key, name) \
|
||||
pfs_os_file_delete_func(key, name, __FILE__, __LINE__)
|
||||
|
||||
# define os_file_delete_if_exists(key, name) \
|
||||
pfs_os_file_delete_if_exists_func(key, name, __FILE__, __LINE__)
|
||||
#else /* UNIV_PFS_IO */
|
||||
|
||||
/* If UNIV_PFS_IO is not defined, these I/O APIs point
|
||||
|
|
@ -341,6 +368,11 @@ to original un-instrumented file I/O APIs */
|
|||
# define os_file_rename(key, oldpath, newpath) \
|
||||
os_file_rename_func(oldpath, newpath)
|
||||
|
||||
# define os_file_delete(key, name) os_file_delete_func(name)
|
||||
|
||||
# define os_file_delete_if_exists(key, name) \
|
||||
os_file_delete_if_exists_func(name)
|
||||
|
||||
#endif /* UNIV_PFS_IO */
|
||||
|
||||
/* File types for directory entry data type */
|
||||
|
|
@ -527,8 +559,8 @@ Deletes a file. The file has to be closed before calling this.
|
|||
@return TRUE if success */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
os_file_delete(
|
||||
/*===========*/
|
||||
os_file_delete_func(
|
||||
/*================*/
|
||||
const char* name); /*!< in: file path as a null-terminated
|
||||
string */
|
||||
|
||||
|
|
@ -537,8 +569,8 @@ Deletes a file if it exists. The file has to be closed before calling this.
|
|||
@return TRUE if success */
|
||||
UNIV_INTERN
|
||||
bool
|
||||
os_file_delete_if_exists(
|
||||
/*=====================*/
|
||||
os_file_delete_if_exists_func(
|
||||
/*==========================*/
|
||||
const char* name); /*!< in: file path as a null-terminated
|
||||
string */
|
||||
/***********************************************************************//**
|
||||
|
|
@ -767,6 +799,38 @@ pfs_os_file_rename_func(
|
|||
const char* newpath,/*!< in: new file path */
|
||||
const char* src_file,/*!< in: file name where func invoked */
|
||||
ulint src_line);/*!< in: line where the func invoked */
|
||||
|
||||
/***********************************************************************//**
|
||||
NOTE! Please use the corresponding macro os_file_delete(), not directly
|
||||
this function!
|
||||
This is the performance schema instrumented wrapper function for
|
||||
os_file_delete()
|
||||
@return TRUE if success */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
pfs_os_file_delete_func(
|
||||
/*====================*/
|
||||
mysql_pfs_key_t key, /*!< in: Performance Schema Key */
|
||||
const char* name, /*!< in: old file path as a null-terminated
|
||||
string */
|
||||
const char* src_file,/*!< in: file name where func invoked */
|
||||
ulint src_line);/*!< in: line where the func invoked */
|
||||
|
||||
/***********************************************************************//**
|
||||
NOTE! Please use the corresponding macro os_file_delete_if_exists(), not
|
||||
directly this function!
|
||||
This is the performance schema instrumented wrapper function for
|
||||
os_file_delete_if_exists()
|
||||
@return TRUE if success */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
pfs_os_file_delete_if_exists_func(
|
||||
/*==============================*/
|
||||
mysql_pfs_key_t key, /*!< in: Performance Schema Key */
|
||||
const char* name, /*!< in: old file path as a null-terminated
|
||||
string */
|
||||
const char* src_file,/*!< in: file name where func invoked */
|
||||
ulint src_line);/*!< in: line where the func invoked */
|
||||
#endif /* UNIV_PFS_IO */
|
||||
|
||||
#ifdef UNIV_HOTBACKUP
|
||||
|
|
@ -896,8 +960,8 @@ os_file_status(
|
|||
The function os_file_dirname returns a directory component of a
|
||||
null-terminated pathname string. In the usual case, dirname returns
|
||||
the string up to, but not including, the final '/', and basename
|
||||
is the component following the final '/'. Trailing '/' charac
|
||||
ters are not counted as part of the pathname.
|
||||
is the component following the final '/'. Trailing '/' characters
|
||||
are not counted as part of the pathname.
|
||||
|
||||
If path does not contain a slash, dirname returns the string ".".
|
||||
|
||||
|
|
|
|||
|
|
@ -386,4 +386,64 @@ pfs_os_file_rename_func(
|
|||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/***********************************************************************//**
|
||||
NOTE! Please use the corresponding macro os_file_delete(), not directly
|
||||
this function!
|
||||
This is the performance schema instrumented wrapper function for
|
||||
os_file_delete()
|
||||
@return TRUE if success */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
pfs_os_file_delete_func(
|
||||
/*====================*/
|
||||
mysql_pfs_key_t key, /*!< in: Performance Schema Key */
|
||||
const char* name, /*!< in: file path as a null-terminated
|
||||
string */
|
||||
const char* src_file, /*!< in: file name where func invoked */
|
||||
ulint src_line) /*!< in: line where the func invoked */
|
||||
{
|
||||
bool result;
|
||||
struct PSI_file_locker* locker = NULL;
|
||||
PSI_file_locker_state state;
|
||||
|
||||
register_pfs_file_close_begin(&state, locker, key, PSI_FILE_DELETE,
|
||||
name, src_file, src_line);
|
||||
|
||||
result = os_file_delete_func(name);
|
||||
|
||||
register_pfs_file_close_end(locker, 0);
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
/***********************************************************************//**
|
||||
NOTE! Please use the corresponding macro os_file_delete_if_exists(), not
|
||||
directly this function!
|
||||
This is the performance schema instrumented wrapper function for
|
||||
os_file_delete_if_exists()
|
||||
@return TRUE if success */
|
||||
UNIV_INLINE
|
||||
bool
|
||||
pfs_os_file_delete_if_exists_func(
|
||||
/*==============================*/
|
||||
mysql_pfs_key_t key, /*!< in: Performance Schema Key */
|
||||
const char* name, /*!< in: file path as a null-terminated
|
||||
string */
|
||||
const char* src_file, /*!< in: file name where func invoked */
|
||||
ulint src_line) /*!< in: line where the func invoked */
|
||||
{
|
||||
bool result;
|
||||
struct PSI_file_locker* locker = NULL;
|
||||
PSI_file_locker_state state;
|
||||
|
||||
register_pfs_file_close_begin(&state, locker, key, PSI_FILE_DELETE,
|
||||
name, src_file, src_line);
|
||||
|
||||
result = os_file_delete_if_exists_func(name);
|
||||
|
||||
register_pfs_file_close_end(locker, 0);
|
||||
|
||||
return(result);
|
||||
}
|
||||
#endif /* UNIV_PFS_IO */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1994, 2013, 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
|
||||
|
|
@ -162,6 +162,12 @@ Inserts a record next to page cursor. Returns pointer to inserted record if
|
|||
succeed, i.e., enough space available, NULL otherwise. The cursor stays at
|
||||
the same logical position, but the physical position may change if it is
|
||||
pointing to a compressed page that was reorganized.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit().
|
||||
|
||||
@return pointer to record if succeed, NULL otherwise */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
|
|
@ -181,6 +187,12 @@ Inserts a record next to page cursor. Returns pointer to inserted record if
|
|||
succeed, i.e., enough space available, NULL otherwise. The cursor stays at
|
||||
the same logical position, but the physical position may change if it is
|
||||
pointing to a compressed page that was reorganized.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit().
|
||||
|
||||
@return pointer to record if succeed, NULL otherwise */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
|
|
@ -205,27 +217,38 @@ page_cur_insert_rec_low(
|
|||
dict_index_t* index, /*!< in: record descriptor */
|
||||
const rec_t* rec, /*!< in: pointer to a physical record */
|
||||
ulint* offsets,/*!< in/out: rec_get_offsets(rec, index) */
|
||||
mtr_t* mtr); /*!< in: mini-transaction handle, or NULL */
|
||||
mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */
|
||||
__attribute__((nonnull(1,2,3,4), warn_unused_result));
|
||||
/***********************************************************//**
|
||||
Inserts a record next to page cursor on a compressed and uncompressed
|
||||
page. Returns pointer to inserted record if succeed, i.e.,
|
||||
enough space available, NULL otherwise.
|
||||
The cursor stays at the same position.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit().
|
||||
|
||||
@return pointer to record if succeed, NULL otherwise */
|
||||
UNIV_INTERN
|
||||
rec_t*
|
||||
page_cur_insert_rec_zip(
|
||||
/*====================*/
|
||||
rec_t** current_rec,/*!< in/out: pointer to current record after
|
||||
which the new record is inserted */
|
||||
buf_block_t* block, /*!< in: buffer block of *current_rec */
|
||||
page_cur_t* cursor, /*!< in/out: page cursor */
|
||||
dict_index_t* index, /*!< in: record descriptor */
|
||||
const rec_t* rec, /*!< in: pointer to a physical record */
|
||||
ulint* offsets,/*!< in/out: rec_get_offsets(rec, index) */
|
||||
mtr_t* mtr); /*!< in: mini-transaction handle, or NULL */
|
||||
mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */
|
||||
__attribute__((nonnull(1,2,3,4), warn_unused_result));
|
||||
/*************************************************************//**
|
||||
Copies records from page to a newly created page, from a given record onward,
|
||||
including that record. Infimum and supremum records are not copied. */
|
||||
including that record. Infimum and supremum records are not copied.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit(). */
|
||||
UNIV_INTERN
|
||||
void
|
||||
page_copy_rec_list_end_to_created_page(
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
|
||||
Copyright (c) 1994, 2013, 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
|
||||
|
|
@ -237,6 +237,12 @@ Inserts a record next to page cursor. Returns pointer to inserted record if
|
|||
succeed, i.e., enough space available, NULL otherwise. The cursor stays at
|
||||
the same logical position, but the physical position may change if it is
|
||||
pointing to a compressed page that was reorganized.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit().
|
||||
|
||||
@return pointer to record if succeed, NULL otherwise */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
|
|
@ -267,8 +273,8 @@ page_cur_tuple_insert(
|
|||
rec, index, *offsets, ULINT_UNDEFINED, heap);
|
||||
|
||||
if (buf_block_get_page_zip(cursor->block)) {
|
||||
rec = page_cur_insert_rec_zip(&cursor->rec, cursor->block,
|
||||
index, rec, *offsets, mtr);
|
||||
rec = page_cur_insert_rec_zip(
|
||||
cursor, index, rec, *offsets, mtr);
|
||||
} else {
|
||||
rec = page_cur_insert_rec_low(cursor->rec,
|
||||
index, rec, *offsets, mtr);
|
||||
|
|
@ -284,6 +290,12 @@ Inserts a record next to page cursor. Returns pointer to inserted record if
|
|||
succeed, i.e., enough space available, NULL otherwise. The cursor stays at
|
||||
the same logical position, but the physical position may change if it is
|
||||
pointing to a compressed page that was reorganized.
|
||||
|
||||
IMPORTANT: The caller will have to update IBUF_BITMAP_FREE
|
||||
if this is a compressed leaf page in a secondary index.
|
||||
This has to be done either within the same mini-transaction,
|
||||
or by invoking ibuf_reset_free_bits() before mtr_commit().
|
||||
|
||||
@return pointer to record if succeed, NULL otherwise */
|
||||
UNIV_INLINE
|
||||
rec_t*
|
||||
|
|
@ -296,8 +308,8 @@ page_cur_rec_insert(
|
|||
mtr_t* mtr) /*!< in: mini-transaction handle, or NULL */
|
||||
{
|
||||
if (buf_block_get_page_zip(cursor->block)) {
|
||||
return(page_cur_insert_rec_zip(&cursor->rec, cursor->block,
|
||||
index, rec, offsets, mtr));
|
||||
return(page_cur_insert_rec_zip(
|
||||
cursor, index, rec, offsets, mtr));
|
||||
} else {
|
||||
return(page_cur_insert_rec_low(cursor->rec,
|
||||
index, rec, offsets, mtr));
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue