This commit is contained in:
Sergei Golubchik 2012-06-16 09:03:07 +02:00
commit bf5df8ccbf
162 changed files with 4381 additions and 1696 deletions

View file

@ -131,6 +131,10 @@ IF (NOT CPACK_GENERATOR)
ENDIF(WIN32)
ENDIF(NOT CPACK_GENERATOR)
IF(DEB)
SET(INSTALL_LAYOUT "DEB")
ENDIF(DEB)
INCLUDE(mysql_version)
INCLUDE(cpack_rpm)
INCLUDE(cpack_source_ignore_files)

View file

@ -1,4 +1,4 @@
MYSQL_VERSION_MAJOR=5
MYSQL_VERSION_MINOR=5
MYSQL_VERSION_PATCH=24
MYSQL_VERSION_PATCH=25
MYSQL_VERSION_EXTRA=

View file

@ -86,6 +86,15 @@
/* Chars needed to store LONGLONG, excluding trailing '\0'. */
#define LONGLONG_LEN 20
/* general_log or slow_log tables under mysql database */
static inline my_bool general_log_or_slow_log_tables(const char *db,
const char *table)
{
return (strcmp(db, "mysql") == 0) &&
((strcmp(table, "general_log") == 0) ||
(strcmp(table, "slow_log") == 0));
}
static void add_load_option(DYNAMIC_STRING *str, const char *option,
const char *option_value);
static ulong find_set(TYPELIB *lib, const char *x, uint length,
@ -2503,6 +2512,7 @@ static uint get_table_structure(char *table, char *db, char *table_type,
"TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'";
FILE *sql_file= md_result_file;
int len;
my_bool is_log_table;
MYSQL_RES *result;
MYSQL_ROW row;
DBUG_ENTER("get_table_structure");
@ -2587,9 +2597,12 @@ static uint get_table_structure(char *table, char *db, char *table_type,
/*
Even if the "table" is a view, we do a DROP TABLE here. The
view-specific code below fills in the DROP VIEW.
We will skip the DROP TABLE for general_log and slow_log, since
those stmts will fail, in case we apply dump by enabling logging.
*/
fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",
opt_quoted_table);
if (!general_log_or_slow_log_tables(db, table))
fprintf(sql_file, "DROP TABLE IF EXISTS %s;\n",
opt_quoted_table);
check_io(sql_file);
}
@ -2701,12 +2714,25 @@ static uint get_table_structure(char *table, char *db, char *table_type,
row= mysql_fetch_row(result);
fprintf(sql_file, (opt_compatible_mode & 3) ? "%s;\n" :
"/*!40101 SET @saved_cs_client = @@character_set_client */;\n"
"/*!40101 SET character_set_client = utf8 */;\n"
"%s;\n"
"/*!40101 SET character_set_client = @saved_cs_client */;\n",
row[1]);
is_log_table= general_log_or_slow_log_tables(db, table);
if (is_log_table)
row[1]+= 13; /* strlen("CREATE TABLE ")= 13 */
if (opt_compatible_mode & 3)
{
fprintf(sql_file,
is_log_table ? "CREATE TABLE IF NOT EXISTS %s;\n" : "%s;\n",
row[1]);
}
else
{
fprintf(sql_file,
"/*!40101 SET @saved_cs_client = @@character_set_client */;\n"
"/*!40101 SET character_set_client = utf8 */;\n"
"%s%s;\n"
"/*!40101 SET character_set_client = @saved_cs_client */;\n",
is_log_table ? "CREATE TABLE IF NOT EXISTS " : "",
row[1]);
}
check_io(sql_file);
mysql_free_result(result);
@ -4315,6 +4341,22 @@ static int dump_all_tables_in_db(char *database)
if (opt_xml)
print_xml_tag(md_result_file, "", "\n", "database", "name=", database, NullS);
if (strcmp(database, "mysql") == 0)
{
char table_type[NAME_LEN];
char ignore_flag;
uint num_fields;
num_fields= get_table_structure((char *) "general_log",
database, table_type, &ignore_flag);
if (num_fields == 0)
verbose_msg("-- Warning: get_table_structure() failed with some internal "
"error for 'general_log' table\n");
num_fields= get_table_structure((char *) "slow_log",
database, table_type, &ignore_flag);
if (num_fields == 0)
verbose_msg("-- Warning: get_table_structure() failed with some internal "
"error for 'slow_log' table\n");
}
if (lock_tables)
{
DYNAMIC_STRING query;

View file

@ -94,8 +94,19 @@ IF(FEATURE_SET)
ENDIF()
OPTION(ENABLED_LOCAL_INFILE "" ON)
SET(WITH_SSL bundled CACHE STRING "")
SET(WITH_ZLIB bundled CACHE STRING "")
IF(RPM)
SET(WITH_SSL system CACHE STRING "")
SET(WITH_ZLIB system CACHE STRING "")
ELSEIF(DEB)
SET(WITH_SSL system CACHE STRING "")
SET(WITH_ZLIB system CACHE STRING "")
SET(WITH_LIBWRAP ON)
SET(WITH_MAX ON)
SET(HAVE_EMBEDDED_PRIVILEGE_CONTROL ON)
ELSE()
SET(WITH_SSL bundled CACHE STRING "")
SET(WITH_ZLIB bundled CACHE STRING "")
ENDIF()
IF(NOT COMPILATION_COMMENT)
SET(COMPILATION_COMMENT "MariaDB Server")

View file

@ -151,7 +151,7 @@ IF(UNIX)
IF(CMAKE_REQUIRED_LIBRARIES)
LIST(REMOVE_DUPLICATES CMAKE_REQUIRED_LIBRARIES)
ENDIF()
ENDIF()
LINK_LIBRARIES(${CMAKE_THREAD_LIBS_INIT})
OPTION(WITH_LIBWRAP "Compile with tcp wrappers support" OFF)

View file

@ -3,7 +3,7 @@
[client]
# Default is Latin1, if you need UTF-8 set this (also in server section)
#character-set-server = utf8
#default-character-set = utf8
[mysqld]
#

View file

@ -70,30 +70,11 @@ endif
CXX=$${MYSQL_BUILD_CXX:-g++} \
CXXFLAGS=$${MYSQL_BUILD_CXXFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DINSTALL_SBINDIR=sbin \
-DMYSQL_DATADIR=/var/lib/mysql \
-DINSTALL_INCLUDEDIR=include/mysql \
-DINSTALL_INFODIR=share/info \
-DINSTALL_MANDIR=share/man \
\
-DMYSQL_SERVER_SUFFIX="-$(DEBVERSION)" \
-DBUILD_CONFIG=mysql_release \
-DCOMPILATION_COMMENT="mariadb.org binary distribution" \
-DSYSTEM_TYPE="debian-linux-gnu" \
-DINSTALL_LAYOUT=DEB \
\
-DENABLED_LOCAL_INFILE=1 \
-DWITH_FAST_MUTEXES=1 \
\
-DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock \
\
-DEXTRA_CHARSETS=all \
-DWITH_LIBWRAP=1 \
-DWITH_SSL=system \
-DWITH_ZLIB=system \
-DWITH_EMBEDDED_SERVER=1 \
-DHAVE_EMBEDDED_PRIVILEGE_CONTROL=ON \
-DWITH_MAX=1'
-DDEB=debian'
touch $@

View file

@ -70,30 +70,11 @@ endif
CXX=$${MYSQL_BUILD_CXX:-g++} \
CXXFLAGS=$${MYSQL_BUILD_CXXFLAGS:-"-O2 -fno-omit-frame-pointer -g -pipe -Wall -Wno-uninitialized"} \
cmake .. \
-DCMAKE_INSTALL_PREFIX=/usr \
-DINSTALL_SBINDIR=sbin \
-DMYSQL_DATADIR=/var/lib/mysql \
-DINSTALL_INCLUDEDIR=include/mysql \
-DINSTALL_INFODIR=share/info \
-DINSTALL_MANDIR=share/man \
\
-DMYSQL_SERVER_SUFFIX="-$(DEBVERSION)" \
-DBUILD_CONFIG=mysql_release \
-DCOMPILATION_COMMENT="mariadb.org binary distribution" \
-DSYSTEM_TYPE="debian-linux-gnu" \
-DINSTALL_LAYOUT=DEB \
\
-DENABLED_LOCAL_INFILE=1 \
-DWITH_FAST_MUTEXES=1 \
\
-DMYSQL_UNIX_ADDR=/var/run/mysqld/mysqld.sock \
\
-DEXTRA_CHARSETS=all \
-DWITH_LIBWRAP=1 \
-DWITH_SSL=system \
-DWITH_ZLIB=system \
-DWITH_EMBEDDED_SERVER=1 \
-DHAVE_EMBEDDED_PRIVILEGE_CONTROL=ON \
-DWITH_MAX=1'
-DDEB=ubuntu'
touch $@

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2000, 2011, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2000, 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
@ -10,8 +10,8 @@
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
along with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
/*
* Vio Lite.

View file

@ -1518,7 +1518,7 @@ sub command_line_setup {
# We make the path absolute, as the server will do a chdir() before usage
unless ( $opt_vardir =~ m,^/, or
(IS_WINDOWS and $opt_vardir =~ m,^[a-z]:/,i) )
(IS_WINDOWS and $opt_vardir =~ m,^[a-z]:[/\\],i) )
{
# Make absolute path, relative test dir
$opt_vardir= "$glob_mysql_test_dir/$opt_vardir";
@ -2717,6 +2717,7 @@ sub setup_vardir() {
# hm, what paths work for debs and for rpms ?
for (<$bindir/lib64/mysql/plugin/*.so>,
<$bindir/lib/mysql/plugin/*.so>,
<$bindir/lib/plugin/*.so>, # bintar
<$bindir/lib/plugin/*.dll>)
{
my $pname=basename($_);
@ -3463,12 +3464,6 @@ sub mysql_install_db {
mtr_add_arg($args, "--lc-messages-dir=%s", $install_lang);
mtr_add_arg($args, "--character-sets-dir=%s", $install_chsdir);
# On some old linux kernels, aio on tmpfs is not supported
# Remove this if/when Bug #58421 fixes this in the server
if ($^O eq "linux" && $opt_mem) {
mtr_add_arg($args, "--loose-skip-innodb-use-native-aio");
}
# InnoDB arguments that affect file location and sizes may
# need to be given to the bootstrap process as well as the
# server process.
@ -4742,6 +4737,7 @@ sub extract_warning_lines ($$) {
qr|Access denied for user|,
qr|Aborted connection|,
qr|table.*is full|,
qr|Linux Native AIO|, # warning that aio does not work on /dev/shm
);
my $matched_lines= [];
@ -5245,13 +5241,6 @@ sub mysqld_arguments ($$$) {
mtr_add_arg($args, "--user=root");
}
# On some old linux kernels, aio on tmpfs is not supported
# Remove this if/when Bug #58421 fixes this in the server
if ($^O eq "linux" && $opt_mem)
{
mtr_add_arg($args, "--loose-skip-innodb-use-native-aio");
}
if (!using_extern() and !$opt_user_args)
{
# Turn on logging to file
@ -5292,6 +5281,7 @@ sub mysqld_arguments ($$$) {
}
elsif ($plugin = mtr_match_prefix($arg, "--plugin-load="))
{
next if $plugin =~ /=$/;
push @plugins, $plugin unless $seen{$plugin};
$seen{$plugin} = 1;
}

View file

@ -0,0 +1,56 @@
#
# Bug#12427262 : 60961: SHOW TABLES VERY SLOW WHEN NOT IN SYSTEM DISK CACHE.
#
create database show_table_lw_db;
use show_table_lw_db;
create table t1 (c1 int);
create table t2 (c1 int);
create table t3 (c1 int);
create table t4 (c1 int);
create table t5 (c1 int);
create table t6 (c1 int);
create table t7 (c1 int);
create table t8 (c1 int);
create table t9 (c1 int);
create table t10 (c1 int);
select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME
like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM'
into @count_read_before;
show tables;
Tables_in_show_table_lw_db
t1
t10
t2
t3
t4
t5
t6
t7
t8
t9
select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME
like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM'
into @count_read_after;
select @count_read_after-@count_read_before;
@count_read_after-@count_read_before
0.000000000000000000000000000000
show full tables;
Tables_in_show_table_lw_db Table_type
t1 BASE TABLE
t10 BASE TABLE
t2 BASE TABLE
t3 BASE TABLE
t4 BASE TABLE
t5 BASE TABLE
t6 BASE TABLE
t7 BASE TABLE
t8 BASE TABLE
t9 BASE TABLE
select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME
like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM'
into @count_read_after;
select @count_read_after-@count_read_before;
@count_read_after-@count_read_before
10.000000000000000000000000000000
drop table t1;
drop database show_table_lw_db;

View file

@ -204,4 +204,30 @@ SELECT BIT_XOR(t1.b) FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.pk=1;
BIT_XOR(t1.b)
0
DROP TABLE t1, t2;
#
# Bug#12713907: STRANGE OPTIMIZE & WRONG RESULT UNDER ORDER BY
# COUNT(*) LIMIT.
#
CREATE TABLE t1 (
id BIGINT(20) ,
member_id_to INT(11) ,
r_date DATE ,
PRIMARY KEY (id,r_date),
KEY r_date_idx (r_date),
KEY t1_idx01 (member_id_to)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(107924526,518491,'2011-05-01'),
(107924527,518491,'2011-05-01'),
(107924534,518491,'2011-06-21'),
(107924535,518491,'2011-06-21'),
(107924542,1601319,'2011-06-21'),
(107924543,1601319,'2011-06-21'),
(107924544,1601319,'2011-06-21'),
(107924545,1601319,'2011-06-21');
SELECT member_id_to, COUNT(*) FROM t1 WHERE r_date =
'2011-06-21' GROUP BY member_id_to ORDER BY 2 LIMIT 1;
member_id_to COUNT(*)
518491 2
DROP TABLE t1;
End of 5.5 tests

View file

@ -0,0 +1,7 @@
set names swe7;
select '' in ('',convert(0,time));
'' in ('',convert(0,time))
1
select case '' when '' then 1 when convert(0,time) then 2 end;
case '' when '' then 1 when convert(0,time) then 2 end
1

View file

@ -5222,3 +5222,48 @@ DROP DATABASE b12809202_db;
# Delete all existing binary logs.
#
RESET MASTER;
#
# Bug#45740 MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM
#
SET @old_log_output_state= @@global.log_output;
SET @old_general_log_state= @@global.general_log;
SET @old_slow_query_log_state= @@global.slow_query_log;
call mtr.add_suppression("Failed to write to mysql.general_log");
SET @@global.log_output="TABLE";
SET @@global.general_log='OFF';
SET @@global.slow_query_log='OFF';
DROP DATABASE mysql;
Warnings:
Error 1146 Table 'mysql.proc' doesn't exist
Error 1146 Table 'mysql.event' doesn't exist
SHOW CREATE TABLE mysql.general_log;
Table Create Table
general_log CREATE TABLE `general_log` (
`event_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`user_host` mediumtext NOT NULL,
`thread_id` int(11) NOT NULL,
`server_id` int(10) unsigned NOT NULL,
`command_type` varchar(64) NOT NULL,
`argument` mediumtext NOT NULL
) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='General log'
SHOW CREATE TABLE mysql.slow_log;
Table Create Table
slow_log CREATE TABLE `slow_log` (
`start_time` timestamp(6) NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`user_host` mediumtext NOT NULL,
`query_time` time(6) NOT NULL,
`lock_time` time(6) NOT NULL,
`rows_sent` int(11) NOT NULL,
`rows_examined` int(11) NOT NULL,
`db` varchar(512) NOT NULL,
`last_insert_id` int(11) NOT NULL,
`insert_id` int(11) NOT NULL,
`server_id` int(10) unsigned NOT NULL,
`sql_text` mediumtext NOT NULL
) ENGINE=CSV DEFAULT CHARSET=utf8 COMMENT='Slow log'
SET @@global.log_output= @old_log_output_state;
SET @@global.slow_query_log= @old_slow_query_log_state;
SET @@global.general_log= @old_general_log_state;
#
# End of 5.1 tests
#

View file

@ -22,3 +22,7 @@ ERROR 42000: Access denied; you need (at least one of) the SUPER privilege(s) fo
**** Clean up ****
set global binlog_format = @saved_binlog_format;
drop user mysqltest_1@localhost;
GRANT REPLICATION CLIENT ON *.* TO 'mysqltest_1'@'localhost';
SHOW MASTER LOGS;
SHOW BINARY LOGS;
DROP USER 'mysqltest_1'@'localhost';

View file

@ -54,3 +54,22 @@ disconnect root;
connection default;
set global binlog_format = @saved_binlog_format;
drop user mysqltest_1@localhost;
# Testing if REPLICATION CLIENT privilege is enough to execute
# SHOW MASTER LOGS and SHOW BINARY.
GRANT REPLICATION CLIENT ON *.* TO 'mysqltest_1'@'localhost';
--connect(rpl,localhost,mysqltest_1,,)
--connection rpl
# We are only interested if the following commands succeed and not on
# their output.
--disable_result_log
SHOW MASTER LOGS;
SHOW BINARY LOGS;
--enable_result_log
# clean up
--disconnect rpl
connection default;
DROP USER 'mysqltest_1'@'localhost';

View file

@ -0,0 +1,6 @@
create table t1 (f1 integer primary key) engine innodb;
alter table t1 add constraint c1 foreign key (f1) references t1(f1);
ERROR HY000: Error on rename of '#sql-temporary' to './test/t1' (errno: 150)
InnoDB: which are not compatible with the new table definition.
InnoDB: has or is referenced in foreign key constraints
drop table t1;

View file

@ -0,0 +1,56 @@
create table t1 (
rowid int,
f1 int,
f2 int,
key i1 (f1, f2),
key i2 (f2)) engine=innodb;
show create table t1;
Table Create Table
t1 CREATE TABLE `t1` (
`rowid` int(11) DEFAULT NULL,
`f1` int(11) DEFAULT NULL,
`f2` int(11) DEFAULT NULL,
KEY `i1` (`f1`,`f2`),
KEY `i2` (`f2`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1
insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL);
start transaction with consistent snapshot;
start transaction;
update t1 set f2 = 4 where f1 = 1 and f2 is null;
(b) Number of rows updated:
select row_count();
row_count()
1
insert into t1 values (3, 1, null);
(b) After update and insert query.
select rowid, f1, f2 from t1;
rowid f1 f2
1 1 10
2 1 4
3 1 NULL
commit;
(a) Before the update statement is executed.
select rowid, f1, f2 from t1;
rowid f1 f2
1 1 10
2 1 NULL
SET SESSION debug_dbug="+d,bug14007649";
update t1 set f2 = 6 where f1 = 1 and f2 is null;
(a) Number of rows updated:
select row_count();
row_count()
1
(a) After the update statement is executed.
select rowid, f1, f2 from t1;
rowid f1 f2
1 1 10
2 1 NULL
3 1 6
commit;
"The trx with consistent snapshot ended."
select rowid, f1, f2 from t1;
rowid f1 f2
1 1 10
2 1 4
3 1 6
drop table t1;

View file

@ -4,11 +4,6 @@
--source include/have_innodb.inc
if (`select plugin_auth_version <= "1.1.8-24.1" from information_schema.plugins where plugin_name='innodb'`)
{
--skip Not fixed in XtraDB 1.1.8-24.1 or earlier
}
# DEBUG_SYNC must be compiled in.
--source include/have_debug_sync.inc

View file

@ -1,10 +1,5 @@
-- source include/have_innodb.inc
if (`select plugin_auth_version <= "1.0.17-13.0" from information_schema.plugins where plugin_name='innodb'`)
{
--skip Not fixed in XtraDB 1.0.17-13.0 or earlier
}
let $MYSQLD_DATADIR= `select @@datadir`;
let $per_table=`select @@innodb_file_per_table`;

View file

@ -1,10 +1,5 @@
--source include/have_innodb.inc
if (`select plugin_auth_version <= "1.0.17-13.0" from information_schema.plugins where plugin_name='innodb'`)
{
--skip Not fixed in XtraDB 1.0.17-13.0 or earlier
}
#
# Check and select innodb lock type
#

View file

@ -0,0 +1,42 @@
# Bug 12902967: Creating self referencing fk on same index unhandled,
# confusing error
#
# Creating a self referencing foreign key on the same
# column/index is an unhandled exception, it should throw a sensible
# error but instead implies that your data dictionary may now be out
# of sync:
--source include/have_innodb.inc
--source include/not_embedded.inc
let error_log= $MYSQLTEST_VARDIR/log/mysqld.1.err;
--source include/restart_mysqld.inc
create table t1 (f1 integer primary key) engine innodb;
# The below statement should produce error message in error log.
# This error message should mention problem with foreign keys
# rather than with data dictionary.
--replace_regex /'\.\/test\/#sql-[0-9a-f_]*'/'#sql-temporary'/
--error ER_ERROR_ON_RENAME
alter table t1 add constraint c1 foreign key (f1) references t1(f1);
--source include/restart_mysqld.inc
perl;
$file = "$ENV{'error_log'}";
open ( FILE, $file) || die "can't open file! ($file)\n";
@lines = <FILE>;
close (FILE);
$count = 0;
foreach $line (reverse @lines) {
if ($line =~ "^InnoDB:") {
++$count;
print "$line";
if ($count == 2) {
last;
}
}
}
EOF
drop table t1;

View file

@ -2,11 +2,6 @@
--source include/have_debug_sync.inc
--source include/not_embedded.inc
if (`select plugin_auth_version <= "1.1.8-24.1" from information_schema.plugins where plugin_name='innodb'`)
{
--skip Not fixed in XtraDB 1.1.8-24.1 or earlier
}
SET DEBUG_SYNC='reset';
# Save the initial number of concurrent sessions

View file

@ -0,0 +1,63 @@
--source include/have_innodb.inc
--source include/have_debug.inc
if (`select plugin_auth_version <= "1.1.8-26.0" from information_schema.plugins where plugin_name='innodb'`)
{
--skip Not fixed in XtraDB 1.1.8-26.0 or earlier
}
create table t1 (
rowid int,
f1 int,
f2 int,
key i1 (f1, f2),
key i2 (f2)) engine=innodb;
show create table t1;
insert into `t1` (rowid, f1, f2) values (1, 1, 10), (2, 1, NULL);
connect (a,localhost,root,,);
connect (b,localhost,root,,);
connection a;
start transaction with consistent snapshot;
connection b;
start transaction;
update t1 set f2 = 4 where f1 = 1 and f2 is null;
-- echo (b) Number of rows updated:
select row_count();
insert into t1 values (3, 1, null);
-- echo (b) After update and insert query.
select rowid, f1, f2 from t1;
commit;
connection a;
-- echo (a) Before the update statement is executed.
select rowid, f1, f2 from t1;
SET SESSION debug_dbug="+d,bug14007649";
update t1 set f2 = 6 where f1 = 1 and f2 is null;
-- echo (a) Number of rows updated:
select row_count();
-- echo (a) After the update statement is executed.
select rowid, f1, f2 from t1;
commit;
--echo "The trx with consistent snapshot ended."
select rowid, f1, f2 from t1;
connection default;
disconnect a;
disconnect b;
drop table t1;

View file

@ -1,3 +1,5 @@
percona_sync_flush: removed from XtraDB-26.0
percona_suppress_log_warning_1592: Feature not merged into MariaDB
percona_log_slow_slave_statements: Feature not merged into MariaDB
percona_log_slow_slave_statements-and-use_global_long_query_time: Feature not merged into MariaDB

View file

@ -0,0 +1,41 @@
include/master-slave.inc
[connection master]
call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
create table tm (b int auto_increment, a int, primary key (a,b)) engine= myisam;
create table ti (b int auto_increment, a int, primary key (a,b)) engine= innodb;
ERROR 42000: Incorrect table definition; there can be only one auto column and it must be defined as a key
create table ti (b int auto_increment, a int, primary key (b,a)) engine= innodb;
set @@binlog_format=statement;
*** autoincrement field is not the first in PK warning must be there: ***
insert into tm set b=null, a=1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe.
show warnings;
Level Code Message
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe.
*** no warning when autoincrement is the first in PK
insert into ti set b=null, a=1;
show warnings;
Level Code Message
create function multi_part_pk_with_autoinc (arg int)
returns int
begin
insert into tm set b=null, a=arg;
return arg;
end//
select multi_part_pk_with_autoinc (3);
multi_part_pk_with_autoinc (3)
3
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe.
*** autoincrement field is not the first in PK warning must be there: ***
show warnings;
Level Code Message
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it invokes a trigger or a stored function that inserts into an AUTO_INCREMENT column. Inserted values cannot be logged correctly.
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. INSERT into autoincrement field which is not the first part in the composed primary key is unsafe.
set @@binlog_format=mixed;
insert into tm set b=null, a=2;
drop table tm, ti;
drop function multi_part_pk_with_autoinc;
include/rpl_end.inc

View file

@ -114,4 +114,23 @@ id c
3 3
[on master]
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT);
CREATE TABLE test.t1 (a INT);
INSERT INTO test.t1 VALUES(1);
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT);
CREATE TRIGGER t1_update AFTER UPDATE ON test.t1 FOR EACH ROW
INSERT INTO test.t_slave VALUES(NULL, ROUND(RAND() * 1000), @c);
SET INSERT_ID=2;
SET @c=2;
SET @@rand_seed1=10000000, @@rand_seed2=1000000;
INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c);
SELECT b into @b FROM test.t5;
UPDATE test.t1 SET a=2;
SELECT a AS 'ONE' into @a FROM test.t_slave;
SELECT c AS 'NULL' into @c FROM test.t_slave;
SELECT b into @b FROM test.t_slave;
drop table test.t5;
drop table test.t1;
drop table test.t_slave;
include/rpl_end.inc

View file

@ -0,0 +1,13 @@
include/master-slave.inc
[connection master]
[connection slave]
SET DEBUG_SYNC= 'after_show_binlog_events SIGNAL on_show_binlog_events WAIT_FOR end';
SHOW BINLOG EVENTS;
[connection slave1]
SET DEBUG_SYNC= 'now WAIT_FOR on_show_binlog_events';
FLUSH LOGS;
SET DEBUG_SYNC= 'now SIGNAL end';
SET DEBUG_SYNC= 'RESET';
[connection slave]
SET DEBUG_SYNC= 'RESET';
include/rpl_end.inc

View file

@ -3,8 +3,8 @@ include/master-slave.inc
include/rpl_restart_server.inc [server_number=2 parameters: --report-port=9000]
include/start_slave.inc
[Slave restarted with the report-port set to some value]
include/assert.inc [The value shown for the slave's port number is 9000 which is the value set for report-port.]
include/rpl_restart_server.inc [server_number=2 parameters: --report-port=]
include/assert.inc [The value shown for the slave's port number is user specified port number which is the value set for report-port.]
include/rpl_restart_server.inc [server_number=2]
include/start_slave.inc
[Slave restarted with the report-port set to the value of slave's port number]
include/assert.inc [The default value shown for the slave's port number is the actual port number of the slave.]

View file

@ -0,0 +1,62 @@
# Test of auto-increment.
#
# BUG#11754117-45670
# Multipart primary key with the autoincrement part not first in it
# is replication unsafe.
#
source include/master-slave.inc;
source include/have_binlog_format_mixed.inc;
source include/have_innodb.inc;
call mtr.add_suppression('Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT.');
--connection master
create table tm (b int auto_increment, a int, primary key (a,b)) engine= myisam;
--error ER_WRONG_AUTO_KEY
create table ti (b int auto_increment, a int, primary key (a,b)) engine= innodb;
create table ti (b int auto_increment, a int, primary key (b,a)) engine= innodb;
set @@binlog_format=statement;
--echo *** autoincrement field is not the first in PK warning must be there: ***
insert into tm set b=null, a=1;
show warnings;
--echo *** no warning when autoincrement is the first in PK
insert into ti set b=null, a=1;
show warnings;
delimiter //;
create function multi_part_pk_with_autoinc (arg int)
returns int
begin
insert into tm set b=null, a=arg;
return arg;
end//
delimiter ;//
select multi_part_pk_with_autoinc (3);
--echo *** autoincrement field is not the first in PK warning must be there: ***
show warnings;
set @@binlog_format=mixed;
insert into tm set b=null, a=2;
sync_slave_with_master;
if (`select count(*) <> 3 from tm`)
{
--echo Wrong result from SELECT on the slave side.
select * from tm;
--die
}
# cleanup
--connection master
drop table tm, ti;
drop function multi_part_pk_with_autoinc;
sync_slave_with_master;
--source include/rpl_end.inc

View file

@ -206,4 +206,64 @@ SELECT * FROM t3;
connection master;
echo [on master];
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
--sync_slave_with_master
#
# BUG#11754117 - 45670: INTVAR_EVENTS FOR FILTERED-OUT QUERY_LOG_EVENTS ARE EXECUTED
# Int-, Rand- and User- var events accompaning a filtered out Query-log-event should
# be filtered as well.
#
connection master;
CREATE TABLE test.t5 (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT); # ignored on slave
CREATE TABLE test.t1 (a INT); # accepted on slave
INSERT INTO test.t1 VALUES(1);
--sync_slave_with_master
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
CREATE TABLE test.t_slave (a INT AUTO_INCREMENT PRIMARY KEY, b INT, c INT);
CREATE TRIGGER t1_update AFTER UPDATE ON test.t1 FOR EACH ROW
INSERT INTO test.t_slave VALUES(NULL, ROUND(RAND() * 1000), @c);
connection master;
SET INSERT_ID=2;
SET @c=2;
SET @@rand_seed1=10000000, @@rand_seed2=1000000;
INSERT INTO t5 VALUES (NULL, ROUND(RAND() * 1000), @c); # to be ignored
SELECT b into @b FROM test.t5;
--let $b_master=`select @b`
UPDATE test.t1 SET a=2; # to run trigger on slave
--sync_slave_with_master
# The proof:
SELECT a AS 'ONE' into @a FROM test.t_slave;
SELECT c AS 'NULL' into @c FROM test.t_slave;
let $count= 1;
let $table= test.t_slave;
source include/wait_until_rows_count.inc;
if (`SELECT @a != 2 and @c != NULL`)
{
SELECT * FROM test.t_slave;
--die Intvar or user var from replication events unexpetedly escaped out to screw a following query applying context.
}
SELECT b into @b FROM test.t_slave;
--let $b_slave=`select @b`
if (`SELECT $b_slave = $b_master`)
{
--echo Might be pure coincidence of two randoms from master and slave table. Don not panic yet.
}
# cleanup BUG#11754117
connection master;
drop table test.t5;
drop table test.t1;
--sync_slave_with_master
drop table test.t_slave;
--source include/rpl_end.inc

View file

@ -0,0 +1,35 @@
# BUG#13979418: SHOW BINLOG EVENTS MAY CRASH THE SERVER
#
# The function mysql_show_binlog_events has a local stack variable
# 'LOG_INFO linfo;', which is assigned to thd->current_linfo, however
# this variable goes out of scope and is destroyed before clean
# thd->current_linfo.
#
# This test case runs SHOW BINLOG EVENTS and FLUSH LOGS to make sure
# that with the fix local variable linfo is valid along all
# mysql_show_binlog_events function scope.
#
--source include/have_debug_sync.inc
--source include/master-slave.inc
--echo [connection slave]
--connection slave
SET DEBUG_SYNC= 'after_show_binlog_events SIGNAL on_show_binlog_events WAIT_FOR end';
--send SHOW BINLOG EVENTS
--connection slave1
--echo [connection slave1]
SET DEBUG_SYNC= 'now WAIT_FOR on_show_binlog_events';
FLUSH LOGS;
SET DEBUG_SYNC= 'now SIGNAL end';
SET DEBUG_SYNC= 'RESET';
--echo [connection slave]
--connection slave
--disable_result_log
--reap
--enable_result_log
SET DEBUG_SYNC= 'RESET';
--connection master
--source include/rpl_end.inc

View file

@ -38,21 +38,23 @@ connection master;
# 9000 is the value of the port we should get.
--let $report_port= query_get_value(SHOW SLAVE HOSTS, Port, 1)
--let assert_text= The value shown for the slave's port number is 9000 which is the value set for report-port.
--let assert_text= The value shown for the slave's port number is user specified port number which is the value set for report-port.
--let assert_cond= $report_port = "9000"
--source include/assert.inc
# Start the server with the report-port being passed with no value. So on SHOW SLAVE HOSTS
# on the master the value of slave's port should be the actual value of the slave port.
connection master;
--let $rpl_server_number= 2
--let $rpl_server_parameters= --report-port=
--let $rpl_server_parameters=
--source include/rpl_restart_server.inc
connection slave;
--source include/start_slave.inc
connection master;
sync_slave_with_master;
--echo [Slave restarted with the report-port set to the value of slave's port number]
connection master;

View file

@ -11,4 +11,5 @@
##############################################################################
innodb_trx_rseg_n_slots_debug_basic: variable innodb_trx_rseg_n_slots_debug is removed in MariaDB
innodb_flush_checkpoint_debug_basic: removed from XtraDB-26.0

View file

@ -1,11 +1,6 @@
--source include/have_innodb.inc
--source include/have_debug.inc
if (`select plugin_auth_version <= "1.1.8-24.1" from information_schema.plugins where plugin_name='innodb'`)
{
--skip Not supported by XtraDB 1.1.8-24.1 or earlier
}
SET @start_global_value = @@global.innodb_trx_rseg_n_slots_debug;
SELECT @start_global_value;

View file

@ -0,0 +1,51 @@
--echo #
--echo # Bug#12427262 : 60961: SHOW TABLES VERY SLOW WHEN NOT IN SYSTEM DISK CACHE.
--echo #
--source include/not_embedded.inc
--source include/have_perfschema.inc
--disable_warnings
create database show_table_lw_db;
use show_table_lw_db;
create table t1 (c1 int);
create table t2 (c1 int);
create table t3 (c1 int);
create table t4 (c1 int);
create table t5 (c1 int);
create table t6 (c1 int);
create table t7 (c1 int);
create table t8 (c1 int);
create table t9 (c1 int);
create table t10 (c1 int);
--enable_warnings
# Query PS to know initial read count for frm file.
select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME
like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM'
into @count_read_before;
show tables;
# Query PS to know read count for frm file after above query. It should
# not be changed as FRM file will not be opened for above query.
select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME
like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM'
into @count_read_after;
select @count_read_after-@count_read_before;
show full tables;
# Query PS to know read count for frm file after above query. COUNT_READ
# will be incremented by 1 as FRM file will be opened for above query.
select Sum(ALL(COUNT_READ)) from performance_schema.file_summary_by_instance where FILE_NAME
like "%show_table_lw_db%" AND FILE_NAME like "%.frm%" AND EVENT_NAME='wait/io/file/sql/FRM'
into @count_read_after;
select @count_read_after-@count_read_before;
--disable_warnings
drop table t1;
drop database show_table_lw_db;
--enable_warnings

View file

@ -144,5 +144,33 @@ SELECT BIT_XOR(t1.b) FROM t1 JOIN t2 ON t1.c=t2.c WHERE t1.pk=1;
DROP TABLE t1, t2;
--echo #
--echo # Bug#12713907: STRANGE OPTIMIZE & WRONG RESULT UNDER ORDER BY
--echo # COUNT(*) LIMIT.
--echo #
CREATE TABLE t1 (
id BIGINT(20) ,
member_id_to INT(11) ,
r_date DATE ,
PRIMARY KEY (id,r_date),
KEY r_date_idx (r_date),
KEY t1_idx01 (member_id_to)
) ENGINE=InnoDB;
INSERT INTO t1 VALUES
(107924526,518491,'2011-05-01'),
(107924527,518491,'2011-05-01'),
(107924534,518491,'2011-06-21'),
(107924535,518491,'2011-06-21'),
(107924542,1601319,'2011-06-21'),
(107924543,1601319,'2011-06-21'),
(107924544,1601319,'2011-06-21'),
(107924545,1601319,'2011-06-21');
SELECT member_id_to, COUNT(*) FROM t1 WHERE r_date =
'2011-06-21' GROUP BY member_id_to ORDER BY 2 LIMIT 1;
DROP TABLE t1;
--echo End of 5.5 tests

View file

@ -0,0 +1,6 @@
#
# MDEV-316 lp:1009085 Assertion failed: warn_item, file item_cmpfunc.cc, line 3613
#
set names swe7;
select '' in ('',convert(0,time));
select case '' when '' then 1 when convert(0,time) then 2 end;

View file

@ -2413,3 +2413,30 @@ RESET MASTER;
# Wait till we reached the initial number of concurrent sessions
--source include/wait_until_count_sessions.inc
--echo #
--echo # Bug#45740 MYSQLDUMP DOESN'T DUMP GENERAL_LOG AND SLOW_QUERY CAUSES RESTORE PROBLEM
--echo #
SET @old_log_output_state= @@global.log_output;
SET @old_general_log_state= @@global.general_log;
SET @old_slow_query_log_state= @@global.slow_query_log;
call mtr.add_suppression("Failed to write to mysql.general_log");
--exec $MYSQL_DUMP -uroot --all-databases > $MYSQLTEST_VARDIR/tmp/bug45740.sql
# Make log_output as table and disabling general_log and slow_log
SET @@global.log_output="TABLE";
SET @@global.general_log='OFF';
SET @@global.slow_query_log='OFF';
DROP DATABASE mysql;
--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/bug45740.sql
SHOW CREATE TABLE mysql.general_log;
SHOW CREATE TABLE mysql.slow_log;
--remove_file $MYSQLTEST_VARDIR/tmp/bug45740.sql
SET @@global.log_output= @old_log_output_state;
SET @@global.slow_query_log= @old_slow_query_log_state;
SET @@global.general_log= @old_general_log_state;
--echo #
--echo # End of 5.1 tests
--echo #

View file

@ -4461,3 +4461,4 @@ SELECT * FROM t1, t2 WHERE a=3 AND a=b;
drop table t1,t2;
--echo End of 5.3 tests

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2008-2011 Monty Program Ab
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2008, 2011, Monty Program Ab
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

View file

@ -1,7 +1,7 @@
#ifndef FIELD_INCLUDED
#define FIELD_INCLUDED
/* Copyright (c) 2000, 2011 Oracle and/or its affiliates.
Copyright (c) 2008-2011 Monty Program Ab
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2008, 2011, Monty Program Ab
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

View file

@ -1,5 +1,7 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2012, Monty Program Ab
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

View file

@ -3032,6 +3032,11 @@ void Item_func_case::fix_length_and_dec()
nagg++;
if (!(found_types= collect_cmp_types(agg, nagg)))
return;
Item *date_arg= 0;
if (found_types & (1 << TIME_RESULT))
date_arg= find_date_time_item(args, arg_count, 0);
if (found_types & (1 << STRING_RESULT))
{
/*
@ -3071,16 +3076,12 @@ void Item_func_case::fix_length_and_dec()
change_item_tree_if_needed(thd, &args[nagg * 2], agg[nagg + 1]);
}
Item *date_arg= 0;
for (i= 0; i <= (uint)TIME_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
DBUG_ASSERT((Item_result)i != ROW_RESULT);
if ((Item_result)i == TIME_RESULT)
date_arg= find_date_time_item(args, arg_count, 0);
if (!(cmp_items[i]=
cmp_item::get_comparator((Item_result)i, date_arg,
cmp_collation.collation)))
@ -4051,15 +4052,15 @@ void Item_func_in::fix_length_and_dec()
}
else
{
if (found_types & (1 << TIME_RESULT))
date_arg= find_date_time_item(args, arg_count, 0);
if (found_types & (1 << STRING_RESULT) &&
agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
return;
for (i= 0; i <= (uint) TIME_RESULT; i++)
{
if (found_types & (1 << i) && !cmp_items[i])
{
if ((Item_result)i == STRING_RESULT &&
agg_arg_charsets_for_comparison(cmp_collation, args, arg_count))
return;
if ((Item_result)i == TIME_RESULT)
date_arg= find_date_time_item(args, arg_count, 0);
if (!cmp_items[i] && !(cmp_items[i]=
cmp_item::get_comparator((Item_result)i, date_arg,
cmp_collation.collation)))

View file

@ -854,6 +854,14 @@ public:
}
}
String *val_str(String *);
longlong val_int()
{ return args[0]->val_int(); }
double val_real()
{ return args[0]->val_real(); }
my_decimal *val_decimal(my_decimal *d)
{ return args[0]->val_decimal(d); }
bool get_date(MYSQL_TIME *ltime, ulonglong fuzzydate)
{ return args[0]->get_date(ltime, fuzzydate); }
void fix_length_and_dec();
const char *func_name() const { return "convert"; }
virtual void print(String *str, enum_query_type query_type);

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2002, 2011, Oracle and/or its affiliates.
Copyright (c) 2010, 2011, Monty Program Ab
/* Copyright (c) 2002, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2012, Monty Program Ab
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

View file

@ -222,6 +222,11 @@ class Relay_log_info;
extern PSI_mutex_key key_LOG_INFO_lock;
#endif
/*
Note that we destroy the lock mutex in the desctructor here.
This means that object instances cannot be destroyed/go out of scope,
until we have reset thd->current_linfo to NULL;
*/
typedef struct st_log_info
{
char log_file_name[FN_REFLEN];

View file

@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2010, 2012, Monty Program Ab
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
@ -5838,11 +5839,12 @@ void Intvar_log_event::print(FILE* file, PRINT_EVENT_INFO* print_event_info)
#endif
#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
/*
Intvar_log_event::do_apply_event()
*/
#if defined(HAVE_REPLICATION)&& !defined(MYSQL_CLIENT)
int Intvar_log_event::do_apply_event(Relay_log_info const *rli)
{
/*
@ -5851,6 +5853,9 @@ int Intvar_log_event::do_apply_event(Relay_log_info const *rli)
*/
const_cast<Relay_log_info*>(rli)->set_flag(Relay_log_info::IN_STMT);
if (rli->deferred_events_collecting)
return rli->deferred_events->add(this);
switch (type) {
case LAST_INSERT_ID_EVENT:
thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt= 1;
@ -5957,6 +5962,9 @@ int Rand_log_event::do_apply_event(Relay_log_info const *rli)
*/
const_cast<Relay_log_info*>(rli)->set_flag(Relay_log_info::IN_STMT);
if (rli->deferred_events_collecting)
return rli->deferred_events->add(this);
thd->rand.seed1= (ulong) seed1;
thd->rand.seed2= (ulong) seed2;
return 0;
@ -5983,6 +5991,29 @@ Rand_log_event::do_shall_skip(Relay_log_info *rli)
return continue_group(rli);
}
/**
Exec deferred Int-, Rand- and User- var events prefixing
a Query-log-event event.
@param thd THD handle
@return false on success, true if a failure in an event applying occurred.
*/
bool slave_execute_deferred_events(THD *thd)
{
bool res= false;
Relay_log_info *rli= thd->rli_slave;
DBUG_ASSERT(rli && (!rli->deferred_events_collecting || rli->deferred_events));
if (!rli->deferred_events_collecting || rli->deferred_events->is_empty())
return res;
res= rli->deferred_events->execute(rli);
return res;
}
#endif /* !MYSQL_CLIENT */
@ -6421,6 +6452,10 @@ int User_var_log_event::do_apply_event(Relay_log_info const *rli)
{
Item *it= 0;
CHARSET_INFO *charset;
if (rli->deferred_events_collecting)
return rli->deferred_events->add(this);
if (!(charset= get_charset(charset_number, MYF(MY_WME))))
return 1;
LEX_STRING user_var_name;

View file

@ -4258,6 +4258,14 @@ private:
const char* log_ident;
uint ident_len;
};
/**
The function is called by slave applier in case there are
active table filtering rules to force gathering events associated
with Query-log-event into an array to execute
them once the fate of the Query is determined for execution.
*/
bool slave_execute_deferred_events(THD *thd);
#endif
int append_query_string(THD *thd, CHARSET_INFO *csinfo,

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2007, 2010, Oracle and/or its affiliates.
/* Copyright (c) 2007, 2012, Oracle and/or its affiliates.
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

View file

@ -1,5 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2012, Monty Program Ab
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

View file

@ -52,8 +52,8 @@ Relay_log_info::Relay_log_info(bool is_slave_recovery)
inited(0), abort_slave(0), slave_running(0), until_condition(UNTIL_NONE),
until_log_pos(0), retried_trans(0),
tables_to_lock(0), tables_to_lock_count(0),
last_event_start_time(0), m_flags(0), row_stmt_start_timestamp(0),
long_find_row_note_printed(false),
last_event_start_time(0), deferred_events(NULL),m_flags(0),
row_stmt_start_timestamp(0), long_find_row_note_printed(false),
m_annotate_event(0)
{
DBUG_ENTER("Relay_log_info::Relay_log_info");

View file

@ -389,6 +389,41 @@ public:
*/
time_t last_event_start_time;
/*
A container to hold on Intvar-, Rand-, Uservar- log-events in case
the slave is configured with table filtering rules.
The withhold events are executed when their parent Query destiny is
determined for execution as well.
*/
Deferred_log_events *deferred_events;
/*
State of the container: true stands for IRU events gathering,
false does for execution, either deferred or direct.
*/
bool deferred_events_collecting;
/*
Returns true if the argument event resides in the containter;
more specifically, the checking is done against the last added event.
*/
bool is_deferred_event(Log_event * ev)
{
return deferred_events_collecting ? deferred_events->is_last(ev) : false;
};
/* The general cleanup that slave applier may need at the end of query. */
inline void cleanup_after_query()
{
if (deferred_events)
deferred_events->rewind();
};
/* The general cleanup that slave applier may need at the end of session. */
void cleanup_after_session()
{
if (deferred_events)
delete deferred_events;
};
/**
Helper function to do after statement completion.

View file

@ -19,6 +19,7 @@
#ifndef MYSQL_CLIENT
#include "unireg.h" // REQUIRED by later includes
#include "rpl_rli.h"
#include "log_event.h"
#include "sql_select.h"
/**
@ -1057,6 +1058,7 @@ table_def::~table_def()
#endif
}
/**
@param even_buf point to the buffer containing serialized event
@param event_len length of the event accounting possible checksum alg
@ -1112,3 +1114,67 @@ bool event_checksum_test(uchar *event_buf, ulong event_len, uint8 alg)
}
return DBUG_EVALUATE_IF("simulate_checksum_test_failure", TRUE, res);
}
#if defined(MYSQL_SERVER) && defined(HAVE_REPLICATION)
Deferred_log_events::Deferred_log_events(Relay_log_info *rli) : last_added(NULL)
{
my_init_dynamic_array(&array, sizeof(Log_event *), 32, 16);
}
Deferred_log_events::~Deferred_log_events()
{
delete_dynamic(&array);
}
int Deferred_log_events::add(Log_event *ev)
{
last_added= ev;
insert_dynamic(&array, (uchar*) &ev);
return 0;
}
bool Deferred_log_events::is_empty()
{
return array.elements == 0;
}
bool Deferred_log_events::execute(Relay_log_info *rli)
{
bool res= false;
DBUG_ASSERT(rli->deferred_events_collecting);
rli->deferred_events_collecting= false;
for (uint i= 0; !res && i < array.elements; i++)
{
Log_event *ev= (* (Log_event **)
dynamic_array_ptr(&array, i));
res= ev->apply_event(rli);
}
rli->deferred_events_collecting= true;
return res;
}
void Deferred_log_events::rewind()
{
/*
Reset preceeding Query log event events which execution was
deferred because of slave side filtering.
*/
if (!is_empty())
{
for (uint i= 0; i < array.elements; i++)
{
Log_event *ev= *(Log_event **) dynamic_array_ptr(&array, i);
delete ev;
}
if (array.elements > array.max_element)
freeze_size(&array);
reset_dynamic(&array);
}
}
#endif

View file

@ -29,7 +29,7 @@
#include "mysql_com.h"
class Relay_log_info;
class Log_event;
/**
A table definition from the master.
@ -262,6 +262,24 @@ CPP_UNNAMED_NS_START
};
CPP_UNNAMED_NS_END
class Deferred_log_events
{
private:
DYNAMIC_ARRAY array;
Log_event *last_added;
public:
Deferred_log_events(Relay_log_info *rli);
~Deferred_log_events();
/* queue for exection at Query-log-event time prior the Query */;
int add(Log_event *ev);
bool is_empty();
bool execute(Relay_log_info *rli);
void rewind();
bool is_last(Log_event *ev) { return ev == last_added; };
};
#endif
// NB. number of printed bit values is limited to sizeof(buf) - 1

View file

@ -6501,6 +6501,9 @@ ER_TABLE_IN_FK_CHECK
ER_UNUSED_1
eng "You should never see it"
ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST
eng "INSERT into autoincrement field which is not the first part in the composed primary key is unsafe."
#
# End of 5.5 error messages.
#

View file

@ -2794,7 +2794,8 @@ static int exec_relay_log_event(THD* thd, Relay_log_info* rli)
/* fall through */
default:
DBUG_PRINT("info", ("Deleting the event after it has been executed"));
delete ev;
if (!rli->is_deferred_event(ev))
delete ev;
break;
}
@ -3458,6 +3459,12 @@ pthread_handler_t handle_slave_sql(void *arg)
goto err_during_init;
}
thd->init_for_queries();
thd->rli_slave= rli;
if ((rli->deferred_events_collecting= rpl_filter->is_on()))
{
rli->deferred_events= new Deferred_log_events(rli);
}
thd->temporary_tables = rli->save_temporary_tables; // restore temp tables
set_thd_in_use_temporary_tables(rli); // (re)set sql_thd in use for saved temp tables
/*

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2002, 2011, Oracle and/or its affiliates.
Copyright (c) 2011, Monty Program Ab
Copyright (c) 2002, 2012, Oracle and/or its affiliates.
Copyright (c) 2011, 2012, Monty Program Ab
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

View file

@ -219,6 +219,7 @@ static bool
has_write_table_with_auto_increment(TABLE_LIST *tables);
static bool
has_write_table_with_auto_increment_and_select(TABLE_LIST *tables);
static bool has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables);
uint cached_open_tables(void)
{
@ -5745,6 +5746,12 @@ bool lock_tables(THD *thd, TABLE_LIST *tables, uint count,
if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables &&
has_write_table_with_auto_increment_and_select(tables))
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_WRITE_AUTOINC_SELECT);
/* Todo: merge all has_write_table_auto_inc with decide_logging_format */
if (thd->variables.binlog_format != BINLOG_FORMAT_ROW && tables)
{
if (has_write_table_auto_increment_not_first_in_pk(tables))
thd->lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST);
}
/*
INSERT...ON DUPLICATE KEY UPDATE on a table with more than one unique keys
@ -9506,6 +9513,32 @@ has_write_table_with_auto_increment_and_select(TABLE_LIST *tables)
return(has_select && has_auto_increment_tables);
}
/*
Tells if there is a table whose auto_increment column is a part
of a compound primary key while is not the first column in
the table definition.
@param tables Table list
@return true if the table exists, fais if does not.
*/
static bool
has_write_table_auto_increment_not_first_in_pk(TABLE_LIST *tables)
{
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
/* we must do preliminary checks as table->table may be NULL */
if (!table->placeholder() &&
table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE)
&& table->table->s->next_number_keypart != 0)
return 1;
}
return 0;
}
/*

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2008-2012 Monty Program Ab
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2008, 2012, Monty Program Ab
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
@ -726,7 +726,7 @@ bool Drop_table_error_handler::handle_condition(THD *thd,
THD::THD()
:Statement(&main_lex, &main_mem_root, STMT_CONVENTIONAL_EXECUTION,
/* statement id */ 0),
rli_fake(0),
rli_fake(0), rli_slave(NULL),
in_sub_stmt(0), log_all_errors(0),
binlog_unsafe_warning_flags(0),
binlog_table_maps(0),
@ -1412,6 +1412,8 @@ THD::~THD()
}
mysql_audit_free_thd(this);
if (rli_slave)
rli_slave->cleanup_after_session();
#endif
free_root(&main_mem_root, MYF(0));
@ -1791,6 +1793,11 @@ void THD::cleanup_after_query()
table_map_for_update= 0;
m_binlog_invoker= FALSE;
#ifndef EMBEDDED_LIBRARY
if (rli_slave)
rli_slave->cleanup_after_query();
#endif
DBUG_VOID_RETURN;
}

View file

@ -1,6 +1,6 @@
/*
Copyright (c) 2000, 2011, Oracle and/or its affiliates.
Copyright (c) 2009-2012, Monty Program Ab
Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2009, 2012, Monty Program Ab
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
@ -1547,6 +1547,8 @@ public:
/* Used to execute base64 coded binlog events in MySQL server */
Relay_log_info* rli_fake;
/* Slave applier execution context */
Relay_log_info* rli_slave;
void reset_for_next_command(bool calculate_userstat);
/*

View file

@ -68,7 +68,8 @@ Query_tables_list::binlog_stmt_unsafe_errcode[BINLOG_STMT_UNSAFE_COUNT] =
ER_BINLOG_UNSAFE_CREATE_REPLACE_SELECT,
ER_BINLOG_UNSAFE_CREATE_SELECT_AUTOINC,
ER_BINLOG_UNSAFE_UPDATE_IGNORE,
ER_BINLOG_UNSAFE_INSERT_TWO_KEYS
ER_BINLOG_UNSAFE_INSERT_TWO_KEYS,
ER_BINLOG_UNSAFE_AUTOINC_NOT_FIRST
};

View file

@ -1433,6 +1433,12 @@ public:
*/
BINLOG_STMT_UNSAFE_INSERT_TWO_KEYS,
/**
INSERT into auto-inc field which is not the first part of composed
primary key.
*/
BINLOG_STMT_UNSAFE_AUTOINC_NOT_FIRST,
/* The last element of this enumeration type. */
BINLOG_STMT_UNSAFE_COUNT
};

View file

@ -2074,6 +2074,11 @@ mysql_execute_command(THD *thd)
}
DBUG_RETURN(0);
}
/*
Execute deferred events first
*/
if (slave_execute_deferred_events(thd))
DBUG_RETURN(-1);
}
else
{
@ -2685,7 +2690,7 @@ end_with_restore_list:
goto error;
#else
{
if (check_global_access(thd, SUPER_ACL))
if (check_global_access(thd, SUPER_ACL | REPL_CLIENT_ACL))
goto error;
res = show_binlogs(thd);
break;

View file

@ -1883,6 +1883,8 @@ bool mysql_show_binlog_events(THD* thd)
File file = -1;
MYSQL_BIN_LOG *binary_log= NULL;
int old_max_allowed_packet= thd->variables.max_allowed_packet;
LOG_INFO linfo;
DBUG_ENTER("mysql_show_binlog_events");
Log_event::init_show_field_list(&field_list);
@ -1925,7 +1927,6 @@ bool mysql_show_binlog_events(THD* thd)
char search_file_name[FN_REFLEN], *name;
const char *log_file_name = lex_mi->log_file_name;
mysql_mutex_t *log_lock = binary_log->get_log_lock();
LOG_INFO linfo;
Log_event* ev;
unit->set_limit(thd->lex->current_select);
@ -2022,6 +2023,8 @@ bool mysql_show_binlog_events(THD* thd)
mysql_mutex_unlock(log_lock);
}
// Check that linfo is still on the function scope.
DEBUG_SYNC(thd, "after_show_binlog_events");
ret= FALSE;

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2010 Oracle and/or its affiliates.
2009-2011 Monty Program Ab
/* Copyright (c) 2000, 2012 Oracle and/or its affiliates.
Copyright (c) 2009, 2012, Monty Program Ab
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
@ -18594,8 +18594,6 @@ check_reverse_order:
join_read_first:join_read_last;
tab->type=JT_NEXT; // Read with index_first(), index_next()
if (table->covering_keys.is_set(best_key) && ! table->key_read)
table->enable_keyread();
if (tab->pre_idx_push_select_cond)
{
tab->set_cond(tab->pre_idx_push_select_cond);
@ -18606,6 +18604,7 @@ check_reverse_order:
orig_cond= 0;
orig_cond_saved= false;
}
table->file->ha_index_or_rnd_end();
if (tab->join->select_options & SELECT_DESCRIBE)
{

View file

@ -1,5 +1,5 @@
/* Copyright (c) 2000, 2012, Oracle and/or its affiliates.
Copyright (c) 2009, 2011, Monty Program Ab
Copyright (c) 2009, 2012, Monty Program Ab
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

View file

@ -238,10 +238,17 @@ uint explain_filename(THD* thd,
{
part_name_len= tmp_p - part_name - 1;
subpart_name= tmp_p + 3;
tmp_p+= 3;
}
else if ((tmp_p[1] == 'Q' || tmp_p[1] == 'q') &&
(tmp_p[2] == 'L' || tmp_p[2] == 'l') &&
tmp_p[3] == '-')
{
name_type= TEMP;
tmp_p+= 4; /* sql- prefix found */
}
else
res= 2;
tmp_p+= 3;
break;
case 'T':
case 't':
@ -6926,21 +6933,47 @@ bool mysql_alter_table(THD *thd,char *new_db, char *new_name,
(void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
}
else if (mysql_rename_table(new_db_type, new_db, tmp_name, new_db,
new_alias, FN_FROM_IS_TMP) ||
((new_name != table_name || new_db != db) && // we also do rename
(need_copy_table != ALTER_TABLE_METADATA_ONLY ||
mysql_rename_table(save_old_db_type, db, table_name, new_db,
new_alias, NO_FRM_RENAME)) &&
Table_triggers_list::change_table_name(thd, db, alias, table_name,
new_db, new_alias)))
new_alias, FN_FROM_IS_TMP))
{
/* Try to get everything back. */
error=1;
(void) quick_rm_table(new_db_type,new_db,new_alias, 0);
error= 1;
(void) quick_rm_table(new_db_type, new_db, tmp_name, FN_IS_TMP);
(void) mysql_rename_table(old_db_type, db, old_name, db, alias,
FN_FROM_IS_TMP);
}
else if (new_name != table_name || new_db != db)
{
if (need_copy_table == ALTER_TABLE_METADATA_ONLY &&
mysql_rename_table(save_old_db_type, db, table_name, new_db,
new_alias, NO_FRM_RENAME))
{
/* Try to get everything back. */
error= 1;
(void) quick_rm_table(new_db_type, new_db, new_alias, 0);
(void) mysql_rename_table(old_db_type, db, old_name, db, alias,
FN_FROM_IS_TMP);
}
else if (Table_triggers_list::change_table_name(thd, db, alias,
table_name, new_db,
new_alias))
{
/* Try to get everything back. */
error= 1;
(void) quick_rm_table(new_db_type, new_db, new_alias, 0);
(void) mysql_rename_table(old_db_type, db, old_name, db,
alias, FN_FROM_IS_TMP);
/*
If we were performing "fast"/in-place ALTER TABLE we also need
to restore old name of table in storage engine as a separate
step, as the above rename affects .FRM only.
*/
if (need_copy_table == ALTER_TABLE_METADATA_ONLY)
{
(void) mysql_rename_table(save_old_db_type, new_db, new_alias,
db, table_name, NO_FRM_RENAME);
}
}
}
if (! error)
(void) quick_rm_table(old_db_type, db, old_name, FN_IS_TMP);

View file

@ -1,4 +1,4 @@
/* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
/* Copyright (c) 2005, 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

View file

@ -3463,6 +3463,8 @@ btr_estimate_n_rows_in_range(
n_rows = n_rows * 2;
}
DBUG_EXECUTE_IF("bug14007649", return(n_rows););
/* Do not estimate the number of rows in the range
to over 1 / 2 of the estimated rows in the whole
table */

View file

@ -1750,8 +1750,6 @@ buf_flush_batch(
}
#endif /* UNIV_DEBUG */
srv_buf_pool_flushed += count;
return(count);
}
@ -1778,13 +1776,6 @@ buf_flush_common(
#endif /* UNIV_DEBUG */
srv_buf_pool_flushed += page_count;
if (flush_type == BUF_FLUSH_LRU) {
/* We keep track of all flushes happening as part of LRU
flush. When estimating the desired rate at which flush_list
should be flushed we factor in this value. */
buf_lru_flush_page_count += page_count;
}
}
/******************************************************************//**

View file

@ -177,7 +177,7 @@ dict_print(void)
monitor printout */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
heap = mem_heap_create(1000);
@ -214,7 +214,7 @@ dict_print(void)
/* Restore the fatal semaphore wait timeout */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
}

View file

@ -1908,7 +1908,7 @@ fil_inc_pending_ops(
if (space == NULL) {
fprintf(stderr,
"InnoDB: Error: trying to do ibuf merge to a"
"InnoDB: Error: trying to do an operation on a"
" dropped tablespace %lu\n",
(ulong) id);
}

View file

@ -4197,6 +4197,31 @@ table_opened:
DBUG_RETURN(0);
}
UNIV_INTERN
handler*
ha_innobase::clone(
/*===============*/
const char* name, /*!< in: table name */
MEM_ROOT* mem_root) /*!< in: memory context */
{
ha_innobase* new_handler;
DBUG_ENTER("ha_innobase::clone");
new_handler = static_cast<ha_innobase*>(handler::clone(name,
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;
}
DBUG_RETURN(new_handler);
}
UNIV_INTERN
uint
ha_innobase::max_supported_key_part_length() const
@ -8546,7 +8571,7 @@ ha_innobase::check(
/* Enlarge the fatal lock wait timeout during CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold += 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold += SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
for (index = dict_table_get_first_index(prebuilt->table);
@ -8687,7 +8712,7 @@ ha_innobase::check(
/* Restore the fatal lock wait timeout after CHECK TABLE. */
mutex_enter(&kernel_mutex);
srv_fatal_semaphore_wait_threshold -= 7200; /* 2 hours */
srv_fatal_semaphore_wait_threshold -= SRV_SEMAPHORE_WAIT_EXTENSION;
mutex_exit(&kernel_mutex);
prebuilt->trx->op_info = "";

View file

@ -133,6 +133,7 @@ class ha_innobase: public handler
const key_map* keys_to_use_for_scanning();
int open(const char *name, int mode, uint test_if_locked);
handler* clone(const char *name, MEM_ROOT *mem_root);
int close(void);
double scan_time();
double read_time(uint index, uint ranges, ha_rows rows);

View file

@ -262,6 +262,7 @@ extern ibool srv_print_latch_waits;
extern ulint srv_activity_count;
extern ulint srv_fatal_semaphore_wait_threshold;
#define SRV_SEMAPHORE_WAIT_EXTENSION 7200
extern ulint srv_dml_needed_delay;
extern mutex_t* kernel_mutex_temp;/* mutex protecting the server, trx structs,

View file

@ -1364,10 +1364,18 @@ innobase_start_or_create_for_mysql(void)
}
# endif /* __WIN__ */
os_aio_init(io_limit,
srv_n_read_io_threads,
srv_n_write_io_threads,
SRV_MAX_N_PENDING_SYNC_IOS);
if (!os_aio_init(io_limit,
srv_n_read_io_threads,
srv_n_write_io_threads,
SRV_MAX_N_PENDING_SYNC_IOS)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Fatal error: cannot initialize AIO"
" sub-system\n");
return(DB_ERROR);
}
fil_init(srv_file_per_table ? 50000 : 5000,
srv_max_n_open_files);

View file

@ -928,6 +928,11 @@ sync_array_print_long_waits(
ibool fatal = FALSE;
double longest_diff = 0;
/* For huge tables, skip the check during CHECK TABLE etc... */
if (fatal_timeout > SRV_SEMAPHORE_WAIT_EXTENSION) {
return(FALSE);
}
#ifdef UNIV_DEBUG_VALGRIND
/* Increase the timeouts if running under valgrind because it executes
extremely slowly. UNIV_DEBUG_VALGRIND does not necessary mean that

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1994, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -42,6 +42,28 @@ Created 6/2/1994 Heikki Tuuri
#include "ibuf0ibuf.h"
#include "trx0trx.h"
/**************************************************************//**
Report that an index page is corrupted. */
UNIV_INTERN
void
btr_corruption_report(
/*==================*/
const buf_block_t* block, /*!< in: corrupted block */
const dict_index_t* index) /*!< in: index tree */
{
fprintf(stderr, "InnoDB: flag mismatch in space %u page %u"
" index %s of table %s\n",
(unsigned) buf_block_get_space(block),
(unsigned) buf_block_get_page_no(block),
index->name, index->table_name);
if (block->page.zip.data) {
buf_page_print(block->page.zip.data,
buf_block_get_zip_size(block),
BUF_PAGE_PRINT_NO_CRASH);
}
buf_page_print(buf_block_get_frame(block), 0, 0);
}
#ifdef UNIV_BLOB_DEBUG
# include "srv0srv.h"
# include "ut0rbt.h"
@ -664,6 +686,12 @@ btr_root_fseg_validate(
{
ulint offset = mach_read_from_2(seg_header + FSEG_HDR_OFFSET);
if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
return (mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space)
&& (offset >= FIL_PAGE_DATA)
&& (offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
}
ut_a(mach_read_from_4(seg_header + FSEG_HDR_SPACE) == space);
ut_a(offset >= FIL_PAGE_DATA);
ut_a(offset <= UNIV_PAGE_SIZE - FIL_PAGE_DATA_END);
@ -698,12 +726,22 @@ btr_root_block_get(
}
ut_a(block);
ut_a((ibool)!!page_is_comp(buf_block_get_frame(block))
== dict_table_is_comp(index->table));
btr_assert_not_corrupted(block, index);
#ifdef UNIV_BTR_DEBUG
if (!dict_index_is_ibuf(index)) {
const page_t* root = buf_block_get_frame(block);
if (UNIV_UNLIKELY(srv_pass_corrupt_table)) {
if (!btr_root_fseg_validate(FIL_PAGE_DATA
+ PAGE_BTR_SEG_LEAF
+ root, space))
return(NULL);
if (!btr_root_fseg_validate(FIL_PAGE_DATA
+ PAGE_BTR_SEG_TOP
+ root, space))
return(NULL);
return(block);
}
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_LEAF
+ root, space));
ut_a(btr_root_fseg_validate(FIL_PAGE_DATA + PAGE_BTR_SEG_TOP
@ -912,28 +950,31 @@ btr_page_alloc_for_ibuf(
/**************************************************************//**
Allocates a new file page to be used in an index tree. NOTE: we assume
that the caller has made the reservation for free extents!
@return new allocated block, x-latched; NULL if out of space */
UNIV_INTERN
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
static __attribute__((nonnull, warn_unused_result))
buf_block_t*
btr_page_alloc(
/*===========*/
btr_page_alloc_low(
/*===============*/
dict_index_t* index, /*!< in: index */
ulint hint_page_no, /*!< in: hint of a good page */
byte file_direction, /*!< in: direction where a possible
page split is made */
ulint level, /*!< in: level where the page is placed
in the tree */
mtr_t* mtr) /*!< in: mtr */
mtr_t* mtr, /*!< in/out: mini-transaction
for the allocation */
mtr_t* init_mtr) /*!< in/out: mtr or another
mini-transaction in which the
page should be initialized.
If init_mtr!=mtr, but the page
is already X-latched in mtr, do
not initialize the page. */
{
fseg_header_t* seg_header;
page_t* root;
buf_block_t* new_block;
ulint new_page_no;
if (dict_index_is_ibuf(index)) {
return(btr_page_alloc_for_ibuf(index, mtr));
}
root = btr_root_get(index, mtr);
@ -947,45 +988,81 @@ btr_page_alloc(
reservation for free extents, and thus we know that a page can
be allocated: */
new_page_no = fseg_alloc_free_page_general(seg_header, hint_page_no,
file_direction, TRUE, mtr);
if (new_page_no == FIL_NULL) {
return(fseg_alloc_free_page_general(
seg_header, hint_page_no, file_direction,
TRUE, mtr, init_mtr));
}
return(NULL);
/**************************************************************//**
Allocates a new file page to be used in an index tree. NOTE: we assume
that the caller has made the reservation for free extents!
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
UNIV_INTERN
buf_block_t*
btr_page_alloc(
/*===========*/
dict_index_t* index, /*!< in: index */
ulint hint_page_no, /*!< in: hint of a good page */
byte file_direction, /*!< in: direction where a possible
page split is made */
ulint level, /*!< in: level where the page is placed
in the tree */
mtr_t* mtr, /*!< in/out: mini-transaction
for the allocation */
mtr_t* init_mtr) /*!< in/out: mini-transaction
for x-latching and initializing
the page */
{
buf_block_t* new_block;
if (dict_index_is_ibuf(index)) {
return(btr_page_alloc_for_ibuf(index, mtr));
}
new_block = buf_page_get(dict_index_get_space(index),
dict_table_zip_size(index->table),
new_page_no, RW_X_LATCH, mtr);
buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
new_block = btr_page_alloc_low(
index, hint_page_no, file_direction, level, mtr, init_mtr);
if (new_block) {
buf_block_dbg_add_level(new_block, SYNC_TREE_NODE_NEW);
}
return(new_block);
}
/**************************************************************//**
Gets the number of pages in a B-tree.
@return number of pages */
@return number of pages, or ULINT_UNDEFINED if the index is unavailable */
UNIV_INTERN
ulint
btr_get_size(
/*=========*/
dict_index_t* index, /*!< in: index */
ulint flag) /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
mtr_t* mtr) /*!< in/out: mini-transaction where index
is s-latched */
{
fseg_header_t* seg_header;
page_t* root;
ulint n;
ulint dummy;
mtr_t mtr;
mtr_start(&mtr);
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
MTR_MEMO_S_LOCK));
mtr_s_lock(dict_index_get_lock(index), &mtr);
if (index->page == FIL_NULL
|| index->to_be_dropped
|| *index->name == TEMP_INDEX_PREFIX) {
return(ULINT_UNDEFINED);
}
root = btr_root_get(index, &mtr);
root = btr_root_get(index, mtr);
if (srv_pass_corrupt_table && !root) {
mtr_commit(&mtr);
mtr_commit(mtr);
return(0);
}
ut_a(root);
@ -993,22 +1070,20 @@ btr_get_size(
if (flag == BTR_N_LEAF_PAGES) {
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
fseg_n_reserved_pages(seg_header, &n, &mtr);
fseg_n_reserved_pages(seg_header, &n, mtr);
} else if (flag == BTR_TOTAL_SIZE) {
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_TOP;
n = fseg_n_reserved_pages(seg_header, &dummy, &mtr);
n = fseg_n_reserved_pages(seg_header, &dummy, mtr);
seg_header = root + PAGE_HEADER + PAGE_BTR_SEG_LEAF;
n += fseg_n_reserved_pages(seg_header, &dummy, &mtr);
n += fseg_n_reserved_pages(seg_header, &dummy, mtr);
} else {
ut_error;
}
mtr_commit(&mtr);
return(n);
}
@ -1090,10 +1165,10 @@ btr_page_free(
buf_block_t* block, /*!< in: block to be freed, x-latched */
mtr_t* mtr) /*!< in: mtr */
{
ulint level;
level = btr_page_get_level(buf_block_get_frame(block), mtr);
const page_t* page = buf_block_get_frame(block);
ulint level = btr_page_get_level(page, mtr);
ut_ad(fil_page_get_type(block->frame) == FIL_PAGE_INDEX);
btr_page_free_low(index, block, level, mtr);
}
@ -1207,9 +1282,11 @@ btr_page_get_father_node_ptr_func(
!= page_no)) {
rec_t* print_rec;
fputs("InnoDB: Dump of the child page:\n", stderr);
buf_page_print(page_align(user_rec), 0);
buf_page_print(page_align(user_rec), 0,
BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: Dump of the parent page:\n", stderr);
buf_page_print(page_align(node_ptr), 0);
buf_page_print(page_align(node_ptr), 0,
BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: Corruption of an index tree: table ", stderr);
ut_print_name(stderr, NULL, TRUE, index->table_name);
@ -1333,16 +1410,12 @@ btr_create(
/* Allocate then the next page to the segment: it will be the
tree root page */
page_no = fseg_alloc_free_page(buf_block_get_frame(
ibuf_hdr_block)
+ IBUF_HEADER
+ IBUF_TREE_SEG_HEADER,
IBUF_TREE_ROOT_PAGE_NO,
FSP_UP, mtr);
ut_ad(page_no == IBUF_TREE_ROOT_PAGE_NO);
block = buf_page_get(space, zip_size, page_no,
RW_X_LATCH, mtr);
block = fseg_alloc_free_page(
buf_block_get_frame(ibuf_hdr_block)
+ IBUF_HEADER + IBUF_TREE_SEG_HEADER,
IBUF_TREE_ROOT_PAGE_NO,
FSP_UP, mtr);
ut_ad(buf_block_get_page_no(block) == IBUF_TREE_ROOT_PAGE_NO);
} else {
#ifdef UNIV_BLOB_DEBUG
if ((type & DICT_CLUSTERED) && !index->blobs) {
@ -1562,7 +1635,7 @@ btr_page_reorganize_low(
ibool success = FALSE;
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
ut_ad(!!page_is_comp(page) == dict_table_is_comp(index->table));
btr_assert_not_corrupted(block, index);
#ifdef UNIV_ZIP_DEBUG
ut_a(!page_zip || page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
@ -1664,8 +1737,8 @@ btr_page_reorganize_low(
if (UNIV_UNLIKELY(data_size1 != data_size2)
|| UNIV_UNLIKELY(max_ins_size1 != max_ins_size2)) {
buf_page_print(page, 0);
buf_page_print(temp_page, 0);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(temp_page, 0, BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Error: page old data size %lu"
" new data size %lu\n"
@ -1676,6 +1749,7 @@ btr_page_reorganize_low(
(unsigned long) data_size1, (unsigned long) data_size2,
(unsigned long) max_ins_size1,
(unsigned long) max_ins_size2);
ut_ad(0);
} else {
success = TRUE;
}
@ -1839,7 +1913,7 @@ btr_root_raise_and_insert(
level = btr_page_get_level(root, mtr);
new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr);
new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, mtr, mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
ut_a(!new_page_zip == !root_page_zip);
@ -2575,7 +2649,7 @@ func_start:
/* 2. Allocate a new page to the index */
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
btr_page_get_level(page, mtr), mtr);
btr_page_get_level(page, mtr), mtr, mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, cursor->index,
@ -3025,15 +3099,16 @@ btr_node_ptr_delete(
ut_a(err == DB_SUCCESS);
if (!compressed) {
btr_cur_compress_if_useful(&cursor, mtr);
btr_cur_compress_if_useful(&cursor, FALSE, mtr);
}
}
/*************************************************************//**
If page is the only on its level, this function moves its records to the
father page, thus reducing the tree height. */
father page, thus reducing the tree height.
@return father block */
static
void
buf_block_t*
btr_lift_page_up(
/*=============*/
dict_index_t* index, /*!< in: index tree */
@ -3150,6 +3225,8 @@ btr_lift_page_up(
}
ut_ad(page_validate(father_page, index));
ut_ad(btr_check_node_ptr(index, father_block, mtr));
return(father_block);
}
/*************************************************************//**
@ -3166,11 +3243,13 @@ UNIV_INTERN
ibool
btr_compress(
/*=========*/
btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift;
the page must not be empty: in record delete
use btr_discard_page if the page would become
empty */
mtr_t* mtr) /*!< in: mtr */
btr_cur_t* cursor, /*!< in/out: cursor on the page to merge
or lift; the page must not be empty:
when deleting records, use btr_discard_page()
if the page would become empty */
ibool adjust, /*!< in: TRUE if should adjust the
cursor position even if compression occurs */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
dict_index_t* index;
ulint space;
@ -3188,13 +3267,15 @@ btr_compress(
ulint* offsets;
ulint data_size;
ulint n_recs;
ulint nth_rec = 0; /* remove bogus warning */
ulint max_ins_size;
ulint max_ins_size_reorg;
block = btr_cur_get_block(cursor);
page = btr_cur_get_page(cursor);
index = btr_cur_get_index(cursor);
ut_a((ibool) !!page_is_comp(page) == dict_table_is_comp(index->table));
btr_assert_not_corrupted(block, index);
ut_ad(mtr_memo_contains(mtr, dict_index_get_lock(index),
MTR_MEMO_X_LOCK));
@ -3214,6 +3295,10 @@ btr_compress(
offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
&father_cursor);
if (adjust) {
nth_rec = page_rec_get_n_recs_before(btr_cur_get_rec(cursor));
}
/* Decide the page to which we try to merge and which will inherit
the locks */
@ -3240,9 +3325,9 @@ btr_compress(
} else {
/* The page is the only one on the level, lift the records
to the father */
btr_lift_page_up(index, block, mtr);
mem_heap_free(heap);
return(TRUE);
merge_block = btr_lift_page_up(index, block, mtr);
goto func_exit;
}
n_recs = page_get_n_recs(page);
@ -3324,6 +3409,10 @@ err_exit:
btr_node_ptr_delete(index, block, mtr);
lock_update_merge_left(merge_block, orig_pred, block);
if (adjust) {
nth_rec += page_rec_get_n_recs_before(orig_pred);
}
} else {
rec_t* orig_succ;
#ifdef UNIV_BTR_DEBUG
@ -3388,7 +3477,6 @@ err_exit:
}
btr_blob_dbg_remove(page, index, "btr_compress");
mem_heap_free(heap);
if (!dict_index_is_clust(index) && page_is_leaf(merge_page)) {
/* Update the free bits of the B-tree page in the
@ -3440,6 +3528,16 @@ err_exit:
btr_page_free(index, block, mtr);
ut_ad(btr_check_node_ptr(index, merge_block, mtr));
func_exit:
mem_heap_free(heap);
if (adjust) {
btr_cur_position(
index,
page_rec_get_nth(merge_block->frame, nth_rec),
merge_block, cursor);
}
return(TRUE);
}
@ -3876,7 +3974,7 @@ btr_index_rec_validate(
(ulong) rec_get_n_fields_old(rec), (ulong) n);
if (dump_on_error) {
buf_page_print(page, 0);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: corrupt record ", stderr);
rec_print_old(stderr, rec);
@ -3914,7 +4012,8 @@ btr_index_rec_validate(
(ulong) i, (ulong) len, (ulong) fixed_size);
if (dump_on_error) {
buf_page_print(page, 0);
buf_page_print(page, 0,
BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: corrupt record ", stderr);
rec_print_new(stderr, rec, offsets);
@ -4124,8 +4223,8 @@ loop:
btr_validate_report2(index, level, block, right_block);
fputs("InnoDB: broken FIL_PAGE_NEXT"
" or FIL_PAGE_PREV links\n", stderr);
buf_page_print(page, 0);
buf_page_print(right_page, 0);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(right_page, 0, BUF_PAGE_PRINT_NO_CRASH);
ret = FALSE;
}
@ -4134,8 +4233,8 @@ loop:
!= page_is_comp(page))) {
btr_validate_report2(index, level, block, right_block);
fputs("InnoDB: 'compact' flag mismatch\n", stderr);
buf_page_print(page, 0);
buf_page_print(right_page, 0);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(right_page, 0, BUF_PAGE_PRINT_NO_CRASH);
ret = FALSE;
@ -4158,8 +4257,8 @@ loop:
fputs("InnoDB: records in wrong order"
" on adjacent pages\n", stderr);
buf_page_print(page, 0);
buf_page_print(right_page, 0);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(right_page, 0, BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: record ", stderr);
rec = page_rec_get_prev(page_get_supremum_rec(page));
@ -4208,8 +4307,8 @@ loop:
fputs("InnoDB: node pointer to the page is wrong\n",
stderr);
buf_page_print(father_page, 0);
buf_page_print(page, 0);
buf_page_print(father_page, 0, BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: node ptr ", stderr);
rec_print(stderr, node_ptr, index);
@ -4241,8 +4340,10 @@ loop:
btr_validate_report1(index, level, block);
buf_page_print(father_page, 0);
buf_page_print(page, 0);
buf_page_print(father_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(page, 0,
BUF_PAGE_PRINT_NO_CRASH);
fputs("InnoDB: Error: node ptrs differ"
" on levels > 0\n"
@ -4287,9 +4388,15 @@ loop:
btr_validate_report1(index, level,
block);
buf_page_print(father_page, 0);
buf_page_print(page, 0);
buf_page_print(right_page, 0);
buf_page_print(
father_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
right_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
}
} else {
page_t* right_father_page
@ -4307,10 +4414,18 @@ loop:
btr_validate_report1(index, level,
block);
buf_page_print(father_page, 0);
buf_page_print(right_father_page, 0);
buf_page_print(page, 0);
buf_page_print(right_page, 0);
buf_page_print(
father_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
right_father_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
right_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
}
if (page_get_page_no(right_father_page)
@ -4324,10 +4439,18 @@ loop:
btr_validate_report1(index, level,
block);
buf_page_print(father_page, 0);
buf_page_print(right_father_page, 0);
buf_page_print(page, 0);
buf_page_print(right_page, 0);
buf_page_print(
father_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
right_father_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
page, 0,
BUF_PAGE_PRINT_NO_CRASH);
buf_page_print(
right_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
}
}
}
@ -4372,6 +4495,12 @@ btr_validate_index(
mtr_x_lock(dict_index_get_lock(index), &mtr);
root = btr_root_get(index, &mtr);
if (UNIV_UNLIKELY(srv_pass_corrupt_table && !root)) {
mtr_commit(&mtr);
return(FALSE);
}
n = btr_page_get_level(root, &mtr);
for (i = 0; i <= n && !trx_is_interrupted(trx); i++) {

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1994, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1994, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@ -18,8 +18,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -438,7 +438,12 @@ btr_cur_search_to_nth_level(
ut_ad(dict_index_check_search_tuple(index, tuple));
ut_ad(!dict_index_is_ibuf(index) || ibuf_inside(mtr));
ut_ad(dtuple_check_typed(tuple));
ut_ad(index->page != FIL_NULL);
UNIV_MEM_INVALID(&cursor->up_match, sizeof cursor->up_match);
UNIV_MEM_INVALID(&cursor->up_bytes, sizeof cursor->up_bytes);
UNIV_MEM_INVALID(&cursor->low_match, sizeof cursor->low_match);
UNIV_MEM_INVALID(&cursor->low_bytes, sizeof cursor->low_bytes);
#ifdef UNIV_DEBUG
cursor->up_match = ULINT_UNDEFINED;
cursor->low_match = ULINT_UNDEFINED;
@ -810,11 +815,11 @@ retry_page_get:
if (level != 0) {
/* x-latch the page */
page = btr_page_get(
buf_block_t* child_block = btr_block_get(
space, zip_size, page_no, RW_X_LATCH, index, mtr);
ut_a((ibool)!!page_is_comp(page)
== dict_table_is_comp(index->table));
page = buf_block_get_frame(child_block);
btr_assert_not_corrupted(child_block, index);
} else {
cursor->low_match = low_match;
cursor->low_bytes = low_bytes;
@ -1959,7 +1964,7 @@ btr_cur_update_in_place(
page_zip = buf_block_get_page_zip(block);
/* Check that enough space is available on the compressed page. */
if (UNIV_LIKELY_NULL(page_zip)
if (page_zip
&& !btr_cur_update_alloc_zip(page_zip, block, index,
rec_offs_size(offsets), FALSE, mtr)) {
return(DB_ZIP_OVERFLOW);
@ -2158,7 +2163,7 @@ any_extern:
ut_a(!page_zip || page_zip_validate(page_zip, page));
#endif /* UNIV_ZIP_DEBUG */
if (UNIV_LIKELY_NULL(page_zip)
if (page_zip
&& !btr_cur_update_alloc_zip(page_zip, block, index,
new_rec_size, TRUE, mtr)) {
err = DB_ZIP_OVERFLOW;
@ -2321,7 +2326,9 @@ btr_cur_pessimistic_update(
/*=======================*/
ulint flags, /*!< in: undo logging, locking, and rollback
flags */
btr_cur_t* cursor, /*!< in: cursor on the record to update */
btr_cur_t* cursor, /*!< in/out: cursor on the record to update;
cursor may become invalid if *big_rec == NULL
|| !(flags & BTR_KEEP_POS_FLAG) */
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
be stored externally by the caller, or NULL */
@ -2463,10 +2470,10 @@ btr_cur_pessimistic_update(
record to be inserted: we have to remember which fields were such */
ut_ad(!page_is_comp(page) || !rec_get_node_ptr_flag(rec));
offsets = rec_get_offsets(rec, index, offsets, ULINT_UNDEFINED, heap);
ut_ad(rec_offs_validate(rec, index, offsets));
n_ext += btr_push_update_extern_fields(new_entry, update, *heap);
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
ut_ad(page_is_comp(page));
if (page_zip_rec_needs_ext(
rec_get_converted_size(index, new_entry, n_ext),
@ -2486,6 +2493,10 @@ make_external:
err = DB_TOO_BIG_RECORD;
goto return_after_reservations;
}
ut_ad(page_is_leaf(page));
ut_ad(dict_index_is_clust(index));
ut_ad(flags & BTR_KEEP_POS_FLAG);
}
if (trx->fake_changes) {
@ -2519,6 +2530,8 @@ make_external:
rec = btr_cur_insert_if_possible(cursor, new_entry, n_ext, mtr);
if (rec) {
page_cursor->rec = rec;
lock_rec_restore_from_page_infimum(btr_cur_get_block(cursor),
rec, block);
@ -2532,7 +2545,10 @@ make_external:
rec, index, offsets, mtr);
}
btr_cur_compress_if_useful(cursor, mtr);
btr_cur_compress_if_useful(
cursor,
big_rec_vec != NULL && (flags & BTR_KEEP_POS_FLAG),
mtr);
if (page_zip && !dict_index_is_clust(index)
&& page_is_leaf(page)) {
@ -2552,6 +2568,21 @@ make_external:
}
}
if (big_rec_vec) {
ut_ad(page_is_leaf(page));
ut_ad(dict_index_is_clust(index));
ut_ad(flags & BTR_KEEP_POS_FLAG);
/* btr_page_split_and_insert() in
btr_cur_pessimistic_insert() invokes
mtr_memo_release(mtr, index->lock, MTR_MEMO_X_LOCK).
We must keep the index->lock when we created a
big_rec, so that row_upd_clust_rec() can store the
big_rec in the same mini-transaction. */
mtr_x_lock(dict_index_get_lock(index), mtr);
}
/* Was the record to be updated positioned as the first user
record on its page? */
was_first = page_cur_is_before_first(page_cursor);
@ -2567,6 +2598,7 @@ make_external:
ut_a(rec);
ut_a(err == DB_SUCCESS);
ut_a(dummy_big_rec == NULL);
page_cursor->rec = rec;
if (dict_index_is_sec_or_ibuf(index)) {
/* Update PAGE_MAX_TRX_ID in the index page header.
@ -3011,10 +3043,12 @@ UNIV_INTERN
ibool
btr_cur_compress_if_useful(
/*=======================*/
btr_cur_t* cursor, /*!< in: cursor on the page to compress;
cursor does not stay valid if compression
occurs */
mtr_t* mtr) /*!< in: mtr */
btr_cur_t* cursor, /*!< in/out: cursor on the page to compress;
cursor does not stay valid if !adjust and
compression occurs */
ibool adjust, /*!< in: TRUE if should adjust the
cursor position even if compression occurs */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ut_ad(mtr_memo_contains(mtr,
dict_index_get_lock(btr_cur_get_index(cursor)),
@ -3023,7 +3057,7 @@ btr_cur_compress_if_useful(
MTR_MEMO_PAGE_X_FIX));
return(btr_cur_compress_recommendation(cursor, mtr)
&& btr_compress(cursor, mtr));
&& btr_compress(cursor, adjust, mtr));
}
/*******************************************************//**
@ -3270,7 +3304,7 @@ return_after_reservations:
mem_heap_free(heap);
if (ret == FALSE) {
ret = btr_cur_compress_if_useful(cursor, mtr);
ret = btr_cur_compress_if_useful(cursor, FALSE, mtr);
}
if (n_extents > 0) {
@ -4011,10 +4045,10 @@ btr_cur_set_ownership_of_extern_field(
byte_val = byte_val | BTR_EXTERN_OWNER_FLAG;
}
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
mach_write_to_1(data + local_len + BTR_EXTERN_LEN, byte_val);
page_zip_write_blob_ptr(page_zip, rec, index, offsets, i, mtr);
} else if (UNIV_LIKELY(mtr != NULL)) {
} else if (mtr != NULL) {
mlog_write_ulint(data + local_len + BTR_EXTERN_LEN, byte_val,
MLOG_1BYTE, mtr);
@ -4253,9 +4287,9 @@ The fields are stored on pages allocated from leaf node
file segment of the index tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN
ulint
btr_store_big_rec_extern_fields_func(
/*=================================*/
enum db_err
btr_store_big_rec_extern_fields(
/*============================*/
dict_index_t* index, /*!< in: index of rec; the index tree
MUST be X-latched */
buf_block_t* rec_block, /*!< in/out: block containing rec */
@ -4264,38 +4298,37 @@ btr_store_big_rec_extern_fields_func(
the "external storage" flags in offsets
will not correspond to rec when
this function returns */
#ifdef UNIV_DEBUG
mtr_t* local_mtr, /*!< in: mtr containing the
latch to rec and to the tree */
#endif /* UNIV_DEBUG */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ibool update_in_place,/*! in: TRUE if the record is updated
in place (not delete+insert) */
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
const big_rec_t*big_rec_vec) /*!< in: vector containing fields
const big_rec_t*big_rec_vec, /*!< in: vector containing fields
to be stored externally */
mtr_t* btr_mtr, /*!< in: mtr containing the
latches to the clustered index */
enum blob_op op) /*! in: operation code */
{
ulint rec_page_no;
byte* field_ref;
ulint extern_len;
ulint store_len;
ulint page_no;
ulint space_id;
ulint zip_size;
ulint prev_page_no;
ulint hint_page_no;
ulint i;
mtr_t mtr;
mem_heap_t* heap = NULL;
ulint rec_page_no;
byte* field_ref;
ulint extern_len;
ulint store_len;
ulint page_no;
ulint space_id;
ulint zip_size;
ulint prev_page_no;
ulint hint_page_no;
ulint i;
mtr_t mtr;
mtr_t* alloc_mtr;
mem_heap_t* heap = NULL;
page_zip_des_t* page_zip;
z_stream c_stream;
z_stream c_stream;
buf_block_t** freed_pages = NULL;
ulint n_freed_pages = 0;
enum db_err error = DB_SUCCESS;
ut_ad(rec_offs_validate(rec, index, offsets));
ut_ad(rec_offs_any_extern(offsets));
ut_ad(mtr_memo_contains(local_mtr, dict_index_get_lock(index),
ut_ad(btr_mtr);
ut_ad(mtr_memo_contains(btr_mtr, dict_index_get_lock(index),
MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains(local_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
ut_ad(mtr_memo_contains(btr_mtr, rec_block, MTR_MEMO_PAGE_X_FIX));
ut_ad(buf_block_get_frame(rec_block) == page_align(rec));
ut_a(dict_index_is_clust(index));
@ -4308,7 +4341,7 @@ btr_store_big_rec_extern_fields_func(
rec_page_no = buf_block_get_page_no(rec_block);
ut_a(fil_page_get_type(page_align(rec)) == FIL_PAGE_INDEX);
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
int err;
/* Zlib deflate needs 128 kilobytes for the default
@ -4324,6 +4357,42 @@ btr_store_big_rec_extern_fields_func(
ut_a(err == Z_OK);
}
if (btr_blob_op_is_update(op)) {
/* Avoid reusing pages that have been previously freed
in btr_mtr. */
if (btr_mtr->n_freed_pages) {
if (heap == NULL) {
heap = mem_heap_create(
btr_mtr->n_freed_pages
* sizeof *freed_pages);
}
freed_pages = mem_heap_alloc(
heap,
btr_mtr->n_freed_pages
* sizeof *freed_pages);
n_freed_pages = 0;
}
/* Because btr_mtr will be committed after mtr, it is
possible that the tablespace has been extended when
the B-tree record was updated or inserted, or it will
be extended while allocating pages for big_rec.
TODO: In mtr (not btr_mtr), write a redo log record
about extending the tablespace to its current size,
and remember the current size. Whenever the tablespace
grows as pages are allocated, write further redo log
records to mtr. (Currently tablespace extension is not
covered by the redo log. If it were, the record would
only be written to btr_mtr, which is committed after
mtr.) */
alloc_mtr = btr_mtr;
} else {
/* Use the local mtr for allocations. */
alloc_mtr = &mtr;
}
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/* All pointers to externally stored columns in the record
must either be zero or they must be pointers to inherited
@ -4338,7 +4407,7 @@ btr_store_big_rec_extern_fields_func(
/* Either this must be an update in place,
or the BLOB must be inherited, or the BLOB pointer
must be zero (will be written in this function). */
ut_a(update_in_place
ut_a(op == BTR_STORE_UPDATE
|| (field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_INHERITED_FLAG)
|| !memcmp(field_ref, field_ref_zero,
BTR_EXTERN_FIELD_REF_SIZE));
@ -4363,7 +4432,7 @@ btr_store_big_rec_extern_fields_func(
prev_page_no = FIL_NULL;
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
int err = deflateReset(&c_stream);
ut_a(err == Z_OK);
@ -4383,18 +4452,24 @@ btr_store_big_rec_extern_fields_func(
hint_page_no = prev_page_no + 1;
}
alloc_another:
block = btr_page_alloc(index, hint_page_no,
FSP_NO_DIR, 0, &mtr);
FSP_NO_DIR, 0, alloc_mtr, &mtr);
if (UNIV_UNLIKELY(block == NULL)) {
mtr_commit(&mtr);
error = DB_OUT_OF_FILE_SPACE;
goto func_exit;
}
if (UNIV_LIKELY_NULL(page_zip)) {
deflateEnd(&c_stream);
mem_heap_free(heap);
}
return(DB_OUT_OF_FILE_SPACE);
if (rw_lock_get_x_lock_count(&block->lock) > 1) {
/* This page must have been freed in
btr_mtr previously. Put it aside, and
allocate another page for the BLOB data. */
ut_ad(alloc_mtr == btr_mtr);
ut_ad(btr_blob_op_is_update(op));
ut_ad(n_freed_pages < btr_mtr->n_freed_pages);
freed_pages[n_freed_pages++] = block;
goto alloc_another;
}
page_no = buf_block_get_page_no(block);
@ -4411,7 +4486,7 @@ btr_store_big_rec_extern_fields_func(
SYNC_EXTERN_STORAGE);
prev_page = buf_block_get_frame(prev_block);
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
mlog_write_ulint(
prev_page + FIL_PAGE_NEXT,
page_no, MLOG_4BYTES, &mtr);
@ -4428,7 +4503,7 @@ btr_store_big_rec_extern_fields_func(
}
if (UNIV_LIKELY_NULL(page_zip)) {
if (page_zip) {
int err;
page_zip_des_t* blob_page_zip;
@ -4511,11 +4586,15 @@ btr_store_big_rec_extern_fields_func(
goto next_zip_page;
}
rec_block = buf_page_get(space_id, zip_size,
rec_page_no,
RW_X_LATCH, &mtr);
buf_block_dbg_add_level(rec_block,
SYNC_NO_ORDER_CHECK);
if (alloc_mtr == &mtr) {
rec_block = buf_page_get(
space_id, zip_size,
rec_page_no,
RW_X_LATCH, &mtr);
buf_block_dbg_add_level(
rec_block,
SYNC_NO_ORDER_CHECK);
}
if (err == Z_STREAM_END) {
mach_write_to_4(field_ref
@ -4549,7 +4628,8 @@ btr_store_big_rec_extern_fields_func(
page_zip_write_blob_ptr(
page_zip, rec, index, offsets,
big_rec_vec->fields[i].field_no, &mtr);
big_rec_vec->fields[i].field_no,
alloc_mtr);
next_zip_page:
prev_page_no = page_no;
@ -4594,19 +4674,23 @@ next_zip_page:
extern_len -= store_len;
rec_block = buf_page_get(space_id, zip_size,
rec_page_no,
RW_X_LATCH, &mtr);
buf_block_dbg_add_level(rec_block,
SYNC_NO_ORDER_CHECK);
if (alloc_mtr == &mtr) {
rec_block = buf_page_get(
space_id, zip_size,
rec_page_no,
RW_X_LATCH, &mtr);
buf_block_dbg_add_level(
rec_block,
SYNC_NO_ORDER_CHECK);
}
mlog_write_ulint(field_ref + BTR_EXTERN_LEN, 0,
MLOG_4BYTES, &mtr);
MLOG_4BYTES, alloc_mtr);
mlog_write_ulint(field_ref
+ BTR_EXTERN_LEN + 4,
big_rec_vec->fields[i].len
- extern_len,
MLOG_4BYTES, &mtr);
MLOG_4BYTES, alloc_mtr);
if (prev_page_no == FIL_NULL) {
btr_blob_dbg_add_blob(
@ -4616,18 +4700,19 @@ next_zip_page:
mlog_write_ulint(field_ref
+ BTR_EXTERN_SPACE_ID,
space_id,
MLOG_4BYTES, &mtr);
space_id, MLOG_4BYTES,
alloc_mtr);
mlog_write_ulint(field_ref
+ BTR_EXTERN_PAGE_NO,
page_no,
MLOG_4BYTES, &mtr);
page_no, MLOG_4BYTES,
alloc_mtr);
mlog_write_ulint(field_ref
+ BTR_EXTERN_OFFSET,
FIL_PAGE_DATA,
MLOG_4BYTES, &mtr);
MLOG_4BYTES,
alloc_mtr);
}
prev_page_no = page_no;
@ -4641,8 +4726,23 @@ next_zip_page:
}
}
if (UNIV_LIKELY_NULL(page_zip)) {
func_exit:
if (page_zip) {
deflateEnd(&c_stream);
}
if (n_freed_pages) {
ulint i;
ut_ad(alloc_mtr == btr_mtr);
ut_ad(btr_blob_op_is_update(op));
for (i = 0; i < n_freed_pages; i++) {
btr_page_free_low(index, freed_pages[i], 0, alloc_mtr);
}
}
if (heap != NULL) {
mem_heap_free(heap);
}
@ -4663,7 +4763,7 @@ next_zip_page:
ut_a(!(field_ref[BTR_EXTERN_LEN] & BTR_EXTERN_OWNER_FLAG));
}
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
return(DB_SUCCESS);
return(error);
}
/*******************************************************************//**
@ -4866,7 +4966,7 @@ btr_free_externally_stored_field(
btr_page_free_low(index, ext_block, 0, &mtr);
if (UNIV_LIKELY(page_zip != NULL)) {
if (page_zip) {
mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO,
next_page_no);
mach_write_to_4(field_ref + BTR_EXTERN_LEN + 4,

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2011, 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
@ -52,12 +52,13 @@ btr_pcur_create_for_mysql(void)
}
/**************************************************************//**
Frees the memory for a persistent cursor object. */
Resets a persistent cursor object, freeing ::old_rec_buf if it is
allocated and resetting the other members to their initial values. */
UNIV_INTERN
void
btr_pcur_free_for_mysql(
/*====================*/
btr_pcur_t* cursor) /*!< in, own: persistent cursor */
btr_pcur_reset(
/*===========*/
btr_pcur_t* cursor) /*!< in, out: persistent cursor */
{
if (cursor->old_rec_buf != NULL) {
@ -66,6 +67,7 @@ btr_pcur_free_for_mysql(
cursor->old_rec_buf = NULL;
}
cursor->btr_cur.index = NULL;
cursor->btr_cur.page_cur.rec = NULL;
cursor->old_rec = NULL;
cursor->old_n_fields = 0;
@ -73,7 +75,17 @@ btr_pcur_free_for_mysql(
cursor->latch_mode = BTR_NO_LATCHES;
cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
}
/**************************************************************//**
Frees the memory for a persistent cursor object. */
UNIV_INTERN
void
btr_pcur_free_for_mysql(
/*====================*/
btr_pcur_t* cursor) /*!< in, own: persistent cursor */
{
btr_pcur_reset(cursor);
mem_free(cursor);
}
@ -127,6 +139,8 @@ btr_pcur_store_position(
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
ut_ad(page_is_leaf(page));
ut_ad(page_get_page_no(page) == index->page);
cursor->old_stored = BTR_PCUR_OLD_STORED;
@ -319,13 +333,19 @@ btr_pcur_restore_position_func(
/* Save the old search mode of the cursor */
old_mode = cursor->search_mode;
if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
switch (cursor->rel_pos) {
case BTR_PCUR_ON:
mode = PAGE_CUR_LE;
} else if (cursor->rel_pos == BTR_PCUR_AFTER) {
break;
case BTR_PCUR_AFTER:
mode = PAGE_CUR_G;
} else {
ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
break;
case BTR_PCUR_BEFORE:
mode = PAGE_CUR_L;
break;
default:
ut_error;
mode = 0;
}
btr_pcur_open_with_no_init_func(index, tuple, mode, latch_mode,
@ -334,25 +354,44 @@ btr_pcur_restore_position_func(
/* Restore the old search mode */
cursor->search_mode = old_mode;
if (cursor->rel_pos == BTR_PCUR_ON
&& btr_pcur_is_on_user_rec(cursor)
&& 0 == cmp_dtuple_rec(tuple, btr_pcur_get_rec(cursor),
rec_get_offsets(
btr_pcur_get_rec(cursor), index,
NULL, ULINT_UNDEFINED, &heap))) {
if (btr_pcur_is_on_user_rec(cursor)) {
switch (cursor->rel_pos) {
case BTR_PCUR_ON:
if (!cmp_dtuple_rec(
tuple, btr_pcur_get_rec(cursor),
rec_get_offsets(btr_pcur_get_rec(cursor),
index, NULL,
ULINT_UNDEFINED, &heap))) {
/* We have to store the NEW value for the modify clock, since
the cursor can now be on a different page! But we can retain
the value of old_rec */
/* We have to store the NEW value for
the modify clock, since the cursor can
now be on a different page! But we can
retain the value of old_rec */
cursor->block_when_stored = btr_pcur_get_block(cursor);
cursor->modify_clock = buf_block_get_modify_clock(
cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
cursor->block_when_stored =
btr_pcur_get_block(cursor);
cursor->modify_clock =
buf_block_get_modify_clock(
cursor->block_when_stored);
cursor->old_stored = BTR_PCUR_OLD_STORED;
mem_heap_free(heap);
mem_heap_free(heap);
return(TRUE);
return(TRUE);
}
break;
case BTR_PCUR_BEFORE:
page_cur_move_to_next(btr_pcur_get_page_cur(cursor));
break;
case BTR_PCUR_AFTER:
page_cur_move_to_prev(btr_pcur_get_page_cur(cursor));
break;
#ifdef UNIV_DEBUG
default:
ut_error;
#endif /* UNIV_DEBUG */
}
}
mem_heap_free(heap);

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1996, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@ -1240,7 +1240,7 @@ cleanup:
index->name, (ulong) block->n_pointers);
rw_lock_x_unlock(btr_search_get_latch(index->id));
btr_search_validate();
ut_ad(btr_search_validate());
} else {
rw_lock_x_unlock(btr_search_get_latch(index->id));
}
@ -2143,7 +2143,9 @@ btr_search_validate(void)
(ulong) block->curr_left_side);
if (n_page_dumps < 20) {
buf_page_print(page, 0);
buf_page_print(
page, 0,
BUF_PAGE_PRINT_NO_CRASH);
n_page_dumps++;
}
}

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1995, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@ -57,7 +57,9 @@ Created 11/5/1995 Heikki Tuuri
/* prototypes for new functions added to ha_innodb.cc */
trx_t* innobase_get_trx();
static inline void _increment_page_get_statistics(buf_block_t* block, trx_t* trx)
static inline
void
_increment_page_get_statistics(buf_block_t* block, trx_t* trx)
{
ulint block_hash;
ulint block_hash_byte;
@ -680,8 +682,12 @@ void
buf_page_print(
/*===========*/
const byte* read_buf, /*!< in: a database page */
ulint zip_size) /*!< in: compressed page size, or
0 for uncompressed pages */
ulint zip_size, /*!< in: compressed page size, or
0 for uncompressed pages */
ulint flags) /*!< in: 0 or
BUF_PAGE_PRINT_NO_CRASH or
BUF_PAGE_PRINT_NO_FULL */
{
#ifndef UNIV_HOTBACKUP
dict_index_t* index;
@ -695,11 +701,14 @@ buf_page_print(
size = UNIV_PAGE_SIZE;
}
ut_print_timestamp(stderr);
fprintf(stderr, " InnoDB: Page dump in ascii and hex (%lu bytes):\n",
(ulong) size);
ut_print_buf(stderr, read_buf, size);
fputs("\nInnoDB: End of page dump\n", stderr);
if (!(flags & BUF_PAGE_PRINT_NO_FULL)) {
ut_print_timestamp(stderr);
fprintf(stderr,
" InnoDB: Page dump in ascii and hex (%lu bytes):\n",
(ulong) size);
ut_print_buf(stderr, read_buf, size);
fputs("\nInnoDB: End of page dump\n", stderr);
}
if (zip_size) {
/* Print compressed page. */
@ -873,6 +882,8 @@ buf_page_print(
stderr);
break;
}
ut_ad(flags & BUF_PAGE_PRINT_NO_CRASH);
}
#ifndef UNIV_HOTBACKUP
@ -1078,11 +1089,8 @@ buf_chunk_init(
for (i = chunk->size; i--; ) {
buf_block_init(buf_pool, block, frame);
UNIV_MEM_INVALID(block->frame, UNIV_PAGE_SIZE);
#ifdef HAVE_valgrind
/* Wipe contents of frame to eliminate a Purify warning */
memset(block->frame, '\0', UNIV_PAGE_SIZE);
#endif
/* Add the block to the free list */
mutex_enter(&buf_pool->free_list_mutex);
UT_LIST_ADD_LAST(free, buf_pool->free, (&block->page));
@ -2768,7 +2776,7 @@ wait_until_unfixed:
block->page.buf_fix_count = 1;
buf_block_set_io_fix(block, BUF_IO_READ);
rw_lock_x_lock_func(&block->lock, 0, file, line);
rw_lock_x_lock_inline(&block->lock, 0, file, line);
UNIV_MEM_INVALID(bpage, sizeof *bpage);
@ -2931,14 +2939,14 @@ wait_until_unfixed:
break;
case RW_S_LATCH:
rw_lock_s_lock_func(&(block->lock), 0, file, line);
rw_lock_s_lock_inline(&(block->lock), 0, file, line);
fix_type = MTR_MEMO_PAGE_S_FIX;
break;
default:
ut_ad(rw_latch == RW_X_LATCH);
rw_lock_x_lock_func(&(block->lock), 0, file, line);
rw_lock_x_lock_inline(&(block->lock), 0, file, line);
fix_type = MTR_MEMO_PAGE_X_FIX;
break;
@ -3023,8 +3031,8 @@ buf_page_optimistic_get(
file, line);
fix_type = MTR_MEMO_PAGE_S_FIX;
} else {
success = rw_lock_x_lock_func_nowait(&(block->lock),
file, line);
success = rw_lock_x_lock_func_nowait_inline(&(block->lock),
file, line);
fix_type = MTR_MEMO_PAGE_X_FIX;
}
@ -3165,8 +3173,8 @@ buf_page_get_known_nowait(
file, line);
fix_type = MTR_MEMO_PAGE_S_FIX;
} else {
success = rw_lock_x_lock_func_nowait(&(block->lock),
file, line);
success = rw_lock_x_lock_func_nowait_inline(&(block->lock),
file, line);
fix_type = MTR_MEMO_PAGE_X_FIX;
}
@ -3186,7 +3194,7 @@ buf_page_get_known_nowait(
ut_a(buf_block_get_state(block) == BUF_BLOCK_FILE_PAGE);
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
#if defined UNIV_DEBUG_FILE_ACCESSES || defined UNIV_DEBUG
ut_a(block->page.file_page_was_freed == FALSE);
ut_a(mode == BUF_KEEP_OLD || !block->page.file_page_was_freed);
#endif
#ifdef UNIV_IBUF_COUNT_DEBUG
@ -3261,8 +3269,8 @@ buf_page_try_get_func(
S-latch. */
fix_type = MTR_MEMO_PAGE_X_FIX;
success = rw_lock_x_lock_func_nowait(&block->lock,
file, line);
success = rw_lock_x_lock_func_nowait_inline(&block->lock,
file, line);
}
if (!success) {
@ -3997,7 +4005,8 @@ corrupt:
"InnoDB: You may have to recover"
" from a backup.\n",
(ulong) bpage->offset);
buf_page_print(frame, buf_page_get_zip_size(bpage));
buf_page_print(frame, buf_page_get_zip_size(bpage),
BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Database page corruption on disk"
" or a failed\n"
@ -5285,34 +5294,32 @@ buf_all_freed(void)
/*********************************************************************//**
Checks that there currently are no pending i/o-operations for the buffer
pool.
@return TRUE if there is no pending i/o */
@return number of pending i/o */
UNIV_INTERN
ibool
buf_pool_check_no_pending_io(void)
/*==============================*/
ulint
buf_pool_check_num_pending_io(void)
/*===============================*/
{
ulint i;
ibool ret = TRUE;
ulint pending_io = 0;
buf_pool_mutex_enter_all();
for (i = 0; i < srv_buf_pool_instances && ret; i++) {
for (i = 0; i < srv_buf_pool_instances; i++) {
const buf_pool_t* buf_pool;
buf_pool = buf_pool_from_array(i);
if (buf_pool->n_pend_reads
+ buf_pool->n_flush[BUF_FLUSH_LRU]
+ buf_pool->n_flush[BUF_FLUSH_LIST]
+ buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE]) {
pending_io += buf_pool->n_pend_reads
+ buf_pool->n_flush[BUF_FLUSH_LRU]
+ buf_pool->n_flush[BUF_FLUSH_LIST]
+ buf_pool->n_flush[BUF_FLUSH_SINGLE_PAGE];
ret = FALSE;
}
}
buf_pool_mutex_exit_all();
return(ret);
return(pending_io);
}
#if 0

View file

@ -767,7 +767,8 @@ buf_flush_buffered_writes(void)
if (UNIV_UNLIKELY
(!page_simple_validate_new(block->frame))) {
corrupted_page:
buf_page_print(block->frame, 0);
buf_page_print(block->frame, 0,
BUF_PAGE_PRINT_NO_CRASH);
ut_print_timestamp(stderr);
fprintf(stderr,
@ -2036,22 +2037,6 @@ buf_flush_list(
buf_pool = buf_pool_from_array(i);
if (lsn_limit != IB_ULONGLONG_MAX) {
buf_page_t* bpage;
buf_flush_list_mutex_enter(buf_pool);
bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
if (!bpage
|| bpage->oldest_modification >= lsn_limit) {
buf_flush_list_mutex_exit(buf_pool);
continue;
} else {
buf_flush_list_mutex_exit(buf_pool);
}
}
if (!buf_flush_start(buf_pool, BUF_FLUSH_LIST)) {
/* We have two choices here. If lsn_limit was
specified then skipping an instance of buffer

View file

@ -48,6 +48,7 @@ Created 11/5/1995 Heikki Tuuri
#include "page0zip.h"
#include "log0recv.h"
#include "srv0srv.h"
#include "srv0start.h"
/** The number of blocks from the LRU_old pointer onward, including
the block pointed to, must be buf_pool->LRU_old_ratio/BUF_LRU_OLD_RATIO_DIV
@ -371,42 +372,278 @@ next_page:
ut_free(page_arr);
}
/******************************************************************//**
While flushing (or removing dirty) pages from a tablespace we don't
want to hog the CPU and resources. Release the buffer pool and block
mutex and try to force a context switch. Then reacquire the same mutexes.
The current page is "fixed" before the release of the mutexes and then
"unfixed" again once we have reacquired the mutexes. */
static
void
buf_flush_yield(
/*============*/
buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
buf_page_t* bpage) /*!< in/out: current page */
{
mutex_t* block_mutex;
ut_ad(buf_pool_mutex_own(buf_pool));
ut_ad(buf_page_in_file(bpage));
block_mutex = buf_page_get_mutex(bpage);
mutex_enter(block_mutex);
/* "Fix" the block so that the position cannot be
changed after we release the buffer pool and
block mutexes. */
buf_page_set_sticky(bpage);
/* Now it is safe to release the buf_pool->mutex. */
buf_pool_mutex_exit(buf_pool);
mutex_exit(block_mutex);
/* Try and force a context switch. */
os_thread_yield();
buf_pool_mutex_enter(buf_pool);
mutex_enter(block_mutex);
/* "Unfix" the block now that we have both the
buffer pool and block mutex again. */
buf_page_unset_sticky(bpage);
mutex_exit(block_mutex);
}
/******************************************************************//**
If we have hogged the resources for too long then release the buffer
pool and flush list mutex and do a thread yield. Set the current page
to "sticky" so that it is not relocated during the yield.
@return TRUE if yielded */
static
ibool
buf_flush_try_yield(
/*================*/
buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
buf_page_t* bpage, /*!< in/out: bpage to remove */
ulint processed) /*!< in: number of pages processed */
{
/* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
loop we release buf_pool->mutex to let other threads
do their job but only if the block is not IO fixed. This
ensures that the block stays in its position in the
flush_list. */
if (bpage != NULL
&& processed >= BUF_LRU_DROP_SEARCH_SIZE
&& buf_page_get_io_fix(bpage) == BUF_IO_NONE) {
buf_flush_list_mutex_exit(buf_pool);
/* Release the buffer pool and block mutex
to give the other threads a go. */
buf_flush_yield(buf_pool, bpage);
buf_flush_list_mutex_enter(buf_pool);
/* Should not have been removed from the flush
list during the yield. However, this check is
not sufficient to catch a remove -> add. */
ut_ad(bpage->in_flush_list);
return(TRUE);
}
return(FALSE);
}
/******************************************************************//**
Removes a single page from a given tablespace inside a specific
buffer pool instance.
@return TRUE if page was removed. */
static
ibool
buf_flush_or_remove_page(
/*=====================*/
buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
buf_page_t* bpage) /*!< in/out: bpage to remove */
{
mutex_t* block_mutex;
ibool 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. */
if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
/* We cannot remove this page during this scan
yet; maybe the system is currently reading it
in, or flushing the modifications to the file */
} else {
/* 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). */
buf_flush_list_mutex_exit(buf_pool);
mutex_enter(block_mutex);
ut_ad(bpage->oldest_modification != 0);
if (bpage->buf_fix_count == 0) {
buf_flush_remove(bpage);
processed = TRUE;
}
mutex_exit(block_mutex);
buf_flush_list_mutex_enter(buf_pool);
}
ut_ad(!mutex_own(block_mutex));
return(processed);
}
/******************************************************************//**
Remove all dirty pages belonging to a given tablespace inside a specific
buffer pool instance when we are deleting the data file(s) of that
tablespace. The pages still remain a part of LRU and are evicted from
the list as they age towards the tail of the LRU. */
the list as they age towards the tail of the LRU.
@return TRUE if all freed. */
static
ibool
buf_flush_or_remove_pages(
/*======================*/
buf_pool_t* buf_pool, /*!< buffer pool instance */
ulint id) /*!< in: target space id for which
to remove or flush pages */
{
buf_page_t* prev;
buf_page_t* bpage;
ulint processed = 0;
ibool all_freed = TRUE;
buf_flush_list_mutex_enter(buf_pool);
for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list);
bpage != NULL;
bpage = prev) {
ut_a(buf_page_in_file(bpage));
ut_ad(bpage->in_flush_list);
/* Save the previous link because once we free the
page we can't rely on the links. */
prev = UT_LIST_GET_PREV(flush_list, bpage);
if (buf_page_get_space(bpage) != id) {
/* Skip this block, as it does not belong to
the target space. */
} else if (!buf_flush_or_remove_page(buf_pool, bpage)) {
/* Remove was unsuccessful, we have to try again
by scanning the entire list from the end. */
all_freed = FALSE;
}
++processed;
/* Yield if we have hogged the CPU and mutexes for too long. */
if (buf_flush_try_yield(buf_pool, prev, processed)) {
/* Reset the batch size counter if we had to yield. */
processed = 0;
}
}
buf_flush_list_mutex_exit(buf_pool);
return(all_freed);
}
/******************************************************************//**
Remove or flush all the dirty pages that belong to a given tablespace
inside a specific buffer pool instance. The pages will remain in the LRU
list and will be evicted from the LRU list as they age and move towards
the tail of the LRU list. */
static
void
buf_LRU_remove_dirty_pages_for_tablespace(
/*======================================*/
buf_flush_dirty_pages(
/*==================*/
buf_pool_t* buf_pool, /*!< buffer pool instance */
ulint id) /*!< in: space id */
{
ibool all_freed;
do {
buf_pool_mutex_enter(buf_pool);
all_freed = buf_flush_or_remove_pages(buf_pool, id);
buf_pool_mutex_exit(buf_pool);
ut_ad(buf_flush_validate(buf_pool));
if (!all_freed) {
os_thread_sleep(20000);
}
} while (!all_freed);
}
/******************************************************************//**
Remove all pages that belong to a given tablespace inside a specific
buffer pool instance when we are DISCARDing the tablespace. */
static
void
buf_LRU_remove_all_pages(
/*=====================*/
buf_pool_t* buf_pool, /*!< buffer pool instance */
ulint id) /*!< in: space id */
{
buf_page_t* bpage;
ibool all_freed;
ulint i;
scan_again:
//buf_pool_mutex_enter(buf_pool);
mutex_enter(&buf_pool->LRU_list_mutex);
rw_lock_x_lock(&buf_pool->page_hash_latch);
buf_flush_list_mutex_enter(buf_pool);
all_freed = TRUE;
for (bpage = UT_LIST_GET_LAST(buf_pool->flush_list), i = 0;
bpage != NULL; ++i) {
for (bpage = UT_LIST_GET_LAST(buf_pool->LRU);
bpage != NULL;
/* No op */) {
buf_page_t* prev_bpage;
mutex_t* block_mutex = NULL;
ut_a(buf_page_in_file(bpage));
ut_ad(bpage->in_LRU_list);
prev_bpage = UT_LIST_GET_PREV(flush_list, bpage);
prev_bpage = UT_LIST_GET_PREV(LRU, bpage);
/* bpage->space and bpage->io_fix are protected by
buf_pool->mutex and block_mutex. It is safe to check
buf_pool->mutex and the block_mutex. It is safe to check
them while holding buf_pool->mutex only. */
if (buf_page_get_space(bpage) != id) {
@ -420,97 +657,89 @@ scan_again:
all_freed = FALSE;
goto next_page;
} else {
block_mutex = buf_page_get_mutex(bpage);
mutex_enter(block_mutex);
if (bpage->buf_fix_count > 0) {
mutex_exit(block_mutex);
/* We cannot remove this page during
this scan yet; maybe the system is
currently reading it in, or flushing
the modifications to the file */
all_freed = FALSE;
goto next_page;
}
}
/* We have to release the flush_list_mutex to obey the
latching order. We are however guaranteed that the page
will stay in the flush_list because buf_flush_remove()
needs buf_pool->mutex as well. */
buf_flush_list_mutex_exit(buf_pool);
block_mutex = buf_page_get_mutex_enter(bpage);
ut_ad(mutex_own(block_mutex));
if (!block_mutex) {
/* It may be impossible case...
Something wrong, so will be scan_again */
all_freed = FALSE;
goto next_page;
#ifdef UNIV_DEBUG
if (buf_debug_prints) {
fprintf(stderr,
"Dropping space %lu page %lu\n",
(ulong) buf_page_get_space(bpage),
(ulong) buf_page_get_page_no(bpage));
}
#endif
if (buf_page_get_state(bpage) != BUF_BLOCK_FILE_PAGE) {
/* Do nothing, because the adaptive hash index
covers uncompressed pages only. */
} else if (((buf_block_t*) bpage)->index) {
ulint page_no;
ulint zip_size;
buf_pool_mutex_exit(buf_pool);
zip_size = buf_page_get_zip_size(bpage);
page_no = buf_page_get_page_no(bpage);
if (bpage->buf_fix_count > 0) {
mutex_exit(block_mutex);
buf_flush_list_mutex_enter(buf_pool);
/* We cannot remove this page during
this scan yet; maybe the system is
currently reading it in, or flushing
the modifications to the file */
/* Note that the following call will acquire
and release block->lock X-latch. */
all_freed = FALSE;
goto next_page;
btr_search_drop_page_hash_when_freed(
id, zip_size, page_no);
goto scan_again;
}
ut_ad(bpage->oldest_modification != 0);
if (bpage->oldest_modification != 0) {
buf_flush_remove(bpage);
}
buf_flush_remove(bpage);
ut_ad(!bpage->in_flush_list);
/* Remove from the LRU list. */
if (buf_LRU_block_remove_hashed_page(bpage, TRUE)
!= BUF_BLOCK_ZIP_FREE) {
buf_LRU_block_free_hashed_page((buf_block_t*) bpage, TRUE);
mutex_exit(block_mutex);
} else {
/* The block_mutex should have been released
by buf_LRU_block_remove_hashed_page() when it
returns BUF_BLOCK_ZIP_FREE. */
ut_ad(block_mutex == &buf_pool->zip_mutex);
}
ut_ad(!mutex_own(block_mutex));
mutex_exit(block_mutex);
buf_flush_list_mutex_enter(buf_pool);
next_page:
bpage = prev_bpage;
if (!bpage) {
break;
}
/* Every BUF_LRU_DROP_SEARCH_SIZE iterations in the
loop we release buf_pool->mutex to let other threads
do their job. */
if (i < BUF_LRU_DROP_SEARCH_SIZE) {
continue;
}
/* We IO-fix the block to make sure that the block
stays in its position in the flush_list. */
if (buf_page_get_io_fix(bpage) != BUF_IO_NONE) {
/* Block is already IO-fixed. We don't
want to change the value. Lets leave
this block alone. */
continue;
}
buf_flush_list_mutex_exit(buf_pool);
block_mutex = buf_page_get_mutex(bpage);
mutex_enter(block_mutex);
buf_page_set_sticky(bpage);
mutex_exit(block_mutex);
/* Now it is safe to release the buf_pool->mutex. */
//buf_pool_mutex_exit(buf_pool);
mutex_exit(&buf_pool->LRU_list_mutex);
rw_lock_x_unlock(&buf_pool->page_hash_latch);
os_thread_yield();
//buf_pool_mutex_enter(buf_pool);
mutex_enter(&buf_pool->LRU_list_mutex);
rw_lock_x_lock(&buf_pool->page_hash_latch);
mutex_enter(block_mutex);
buf_page_unset_sticky(bpage);
mutex_exit(block_mutex);
buf_flush_list_mutex_enter(buf_pool);
ut_ad(bpage->in_flush_list);
i = 0;
}
// buf_pool_mutex_exit(buf_pool);
mutex_exit(&buf_pool->LRU_list_mutex);
rw_lock_x_unlock(&buf_pool->page_hash_latch);
buf_flush_list_mutex_exit(buf_pool);
ut_ad(buf_flush_validate(buf_pool));
if (!all_freed) {
os_thread_sleep(20000);
@ -520,28 +749,46 @@ next_page:
}
/******************************************************************//**
Invalidates all pages belonging to a given tablespace when we are deleting
the data file(s) of that tablespace. */
Removes all pages belonging to a given tablespace. */
UNIV_INTERN
void
buf_LRU_invalidate_tablespace(
buf_LRU_flush_or_remove_pages(
/*==========================*/
ulint id) /*!< in: space id */
ulint id, /*!< in: space id */
enum buf_remove_t buf_remove)/*!< in: remove or flush
strategy */
{
ulint i;
ulint i;
/* Before we attempt to drop pages one by one we first
attempt to drop page hash index entries in batches to make
it more efficient. The batching attempt is a best effort
attempt and does not guarantee that all pages hash entries
will be dropped. We get rid of remaining page hash entries
one by one below. */
for (i = 0; i < srv_buf_pool_instances; i++) {
buf_pool_t* buf_pool;
buf_pool = buf_pool_from_array(i);
buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
buf_LRU_remove_dirty_pages_for_tablespace(buf_pool, id);
switch (buf_remove) {
case BUF_REMOVE_ALL_NO_WRITE:
/* A DISCARD tablespace case. Remove AHI entries
and evict all pages from LRU. */
/* Before we attempt to drop pages hash entries
one by one we first attempt to drop page hash
index entries in batches to make it more
efficient. The batching attempt is a best effort
attempt and does not guarantee that all pages
hash entries will be dropped. We get rid of
remaining page hash entries one by one below. */
buf_LRU_drop_page_hash_for_tablespace(buf_pool, id);
buf_LRU_remove_all_pages(buf_pool, id);
break;
case BUF_REMOVE_FLUSH_NO_WRITE:
/* A DROP table case. AHI entries are already
removed. No need to evict all pages from LRU
list. Just evict pages from flush list without
writing. */
buf_flush_dirty_pages(buf_pool, id);
break;
}
}
}
@ -2260,6 +2507,7 @@ func_exit:
/********************************************************************//**
Dump the LRU page list to the specific file. */
#define LRU_DUMP_FILE "ib_lru_dump"
#define LRU_DUMP_TEMP_FILE "ib_lru_dump.tmp"
UNIV_INTERN
ibool
@ -2294,8 +2542,10 @@ buf_LRU_file_dump(void)
goto end;
}
dump_file = os_file_create(innodb_file_temp_key, LRU_DUMP_FILE, OS_FILE_OVERWRITE,
OS_FILE_NORMAL, OS_DATA_FILE, &success);
dump_file = os_file_create(innodb_file_temp_key, LRU_DUMP_TEMP_FILE,
OS_FILE_OVERWRITE, OS_FILE_NORMAL, OS_DATA_FILE,
&success);
if (!success) {
os_file_get_last_error(TRUE);
fprintf(stderr,
@ -2324,6 +2574,13 @@ buf_LRU_file_dump(void)
offset++;
if (offset == UNIV_PAGE_SIZE/4) {
if (srv_shutdown_state != SRV_SHUTDOWN_NONE) {
success = 0;
fprintf(stderr,
" InnoDB: stopped dumping lru"
" pages because of server"
" shutdown.\n");
}
success = os_file_write(LRU_DUMP_FILE, dump_file, buffer,
(buffers << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL,
(buffers >> (32 - UNIV_PAGE_SIZE_SHIFT)),
@ -2363,8 +2620,16 @@ buf_LRU_file_dump(void)
ret = TRUE;
end:
if (dump_file != (os_file_t) -1)
if (dump_file != (os_file_t) -1) {
if (success) {
success = os_file_flush(dump_file, TRUE);
}
os_file_close(dump_file);
}
if (success) {
success = os_file_rename(innodb_file_temp_key,
LRU_DUMP_TEMP_FILE, LRU_DUMP_FILE);
}
if (buffer_base)
ut_free(buffer_base);
@ -2410,6 +2675,7 @@ buf_LRU_file_restore(void)
dump_record_t* records = NULL;
ulint size;
ulint size_high;
ulint recsize = sizeof(dump_record_t);
ulint length;
dump_file = os_file_create_simple_no_error_handling(innodb_file_temp_key,
@ -2417,7 +2683,14 @@ buf_LRU_file_restore(void)
if (!success || !os_file_get_size(dump_file, &size, &size_high)) {
os_file_get_last_error(TRUE);
fprintf(stderr,
" InnoDB: cannot open %s\n", LRU_DUMP_FILE);
" InnoDB: cannot open %s, "
" buffer pool preload not done.\n", LRU_DUMP_FILE);
goto end;
}
if (size == 0 || size_high > 0 || size % recsize) {
fprintf(stderr, " InnoDB: broken LRU dump file,"
" buffer pool preload not done\n");
goto end;
}
@ -2501,6 +2774,14 @@ buf_LRU_file_restore(void)
if (offset % 16 == 15) {
os_aio_simulated_wake_handler_threads();
buf_flush_free_margins(FALSE);
/* skip loading of the rest of the file if we are
terminating anyway */
if(srv_shutdown_state != SRV_SHUTDOWN_NONE) {
fprintf(stderr,
" InnoDB: stopped loading lru pages"
" because of server shutdown\n");
break;
}
}
zip_size = fil_space_get_zip_size(space_id);

View file

@ -239,6 +239,166 @@ dict_hdr_create(
return(TRUE);
}
/*****************************************************************//**
Verifies the SYS_STATS table by scanning its clustered index. This
function may only be called at InnoDB startup time.
@return TRUE if SYS_STATS was verified successfully */
UNIV_INTERN
ibool
dict_verify_xtradb_sys_stats(void)
/*==============================*/
{
dict_index_t* sys_stats_index;
ulint saved_srv_pass_corrupt_table = srv_pass_corrupt_table;
ibool result;
sys_stats_index = dict_table_get_first_index(dict_sys->sys_stats);
/* Since this may be called only during server startup, avoid hitting
various asserts by using XtraDB pass_corrupt_table option. */
srv_pass_corrupt_table = 1;
result = btr_validate_index(sys_stats_index, NULL);
srv_pass_corrupt_table = saved_srv_pass_corrupt_table;
return result;
}
/*****************************************************************//**
Creates the B-tree for the SYS_STATS clustered index, adds the XtraDB
mark and the id of the index to the dictionary header page. Rewrites
both passed args. */
static
void
dict_create_xtradb_sys_stats(
/*=========================*/
dict_hdr_t** dict_hdr, /*!< in/out: dictionary header */
mtr_t* mtr) /*!< in/out: mtr */
{
ulint root_page_no;
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_STATS_ID,
dict_ind_redundant, mtr);
if (root_page_no == FIL_NULL) {
fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
srv_use_sys_stats_table = FALSE;
} else {
mlog_write_ulint(*dict_hdr + DICT_HDR_STATS, root_page_no,
MLOG_4BYTES, mtr);
mlog_write_ull(*dict_hdr + DICT_HDR_XTRADB_MARK,
DICT_HDR_XTRADB_FLAG, mtr);
}
mtr_commit(mtr);
/* restart mtr */
mtr_start(mtr);
*dict_hdr = dict_hdr_get(mtr);
}
/*****************************************************************//**
Create the table and index structure of SYS_STATS for the dictionary
cache and add it there. If called for the first time, also support
wrong root page id injection for testing purposes. */
static
void
dict_add_to_cache_xtradb_sys_stats(
/*===============================*/
ibool first_time __attribute__((unused)),
/*!< in: first invocation flag. If
TRUE, optionally inject wrong root page
id */
mem_heap_t* heap, /*!< in: memory heap for table/index
allocation */
dict_hdr_t* dict_hdr, /*!< in: dictionary header */
mtr_t* mtr) /*!< in: mtr */
{
dict_table_t* table;
dict_index_t* index;
ulint root_page_id;
ulint error;
table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
table->n_mysql_handles_opened = 1; /* for pin */
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
/* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
#endif
#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
#endif
table->id = DICT_STATS_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_stats = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "INDEX_ID", 0);
dict_mem_index_add_field(index, "KEY_COLS", 0);
index->id = DICT_STATS_ID;
root_page_id = mtr_read_ulint(dict_hdr + DICT_HDR_STATS, MLOG_4BYTES,
mtr);
#ifdef UNIV_DEBUG
if ((srv_sys_stats_root_page != 0) && first_time)
root_page_id = srv_sys_stats_root_page;
#endif
error = dict_index_add_to_cache(table, index, root_page_id, FALSE);
ut_a(error == DB_SUCCESS);
mem_heap_empty(heap);
}
/*****************************************************************//**
Discard the existing dictionary cache SYS_STATS information, create and
add it there anew. Does not touch the old SYS_STATS tablespace page
under the assumption that they are corrupted or overwritten for other
purposes. */
UNIV_INTERN
void
dict_recreate_xtradb_sys_stats(void)
/*================================*/
{
mtr_t mtr;
dict_hdr_t* dict_hdr;
dict_index_t* sys_stats_clust_idx;
mem_heap_t* heap;
heap = mem_heap_create(450);
mutex_enter(&(dict_sys->mutex));
sys_stats_clust_idx = dict_table_get_first_index(dict_sys->sys_stats);
dict_index_remove_from_cache(dict_sys->sys_stats, sys_stats_clust_idx);
dict_table_remove_from_cache(dict_sys->sys_stats);
dict_sys->sys_stats = NULL;
mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr);
dict_create_xtradb_sys_stats(&dict_hdr, &mtr);
dict_add_to_cache_xtradb_sys_stats(FALSE, heap, dict_hdr, &mtr);
mem_heap_free(heap);
mtr_commit(&mtr);
mutex_exit(&(dict_sys->mutex));
}
/*****************************************************************//**
Initializes the data dictionary memory structures when the database is
started. This function is also called when the data dictionary is created. */
@ -254,13 +414,13 @@ dict_boot(void)
mtr_t mtr;
ulint error;
heap = mem_heap_create(450);
mtr_start(&mtr);
/* Create the hash tables etc. */
dict_init();
heap = mem_heap_create(450);
mutex_enter(&(dict_sys->mutex));
/* Get the dictionary header */
@ -268,25 +428,9 @@ dict_boot(void)
if (mach_read_from_8(dict_hdr + DICT_HDR_XTRADB_MARK)
!= DICT_HDR_XTRADB_FLAG) {
/* not extended yet by XtraDB, need to be extended */
ulint root_page_no;
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
DICT_HDR_SPACE, 0, DICT_STATS_ID,
dict_ind_redundant, &mtr);
if (root_page_no == FIL_NULL) {
fprintf(stderr, "InnoDB: Warning: failed to create SYS_STATS btr.\n");
srv_use_sys_stats_table = FALSE;
} else {
mlog_write_ulint(dict_hdr + DICT_HDR_STATS, root_page_no,
MLOG_4BYTES, &mtr);
mlog_write_ull(dict_hdr + DICT_HDR_XTRADB_MARK,
DICT_HDR_XTRADB_FLAG, &mtr);
}
mtr_commit(&mtr);
/* restart mtr */
mtr_start(&mtr);
dict_hdr = dict_hdr_get(&mtr);
/* not extended yet by XtraDB, need to be extended */
dict_create_xtradb_sys_stats(&dict_hdr, &mtr);
}
/* Because we only write new row ids to disk-based data structure
@ -465,42 +609,7 @@ dict_boot(void)
FALSE);
ut_a(error == DB_SUCCESS);
/*-------------------------*/
table = dict_mem_table_create("SYS_STATS", DICT_HDR_SPACE, 4, 0);
table->n_mysql_handles_opened = 1; /* for pin */
dict_mem_table_add_col(table, heap, "INDEX_ID", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "KEY_COLS", DATA_INT, 0, 4);
dict_mem_table_add_col(table, heap, "DIFF_VALS", DATA_BINARY, 0, 0);
dict_mem_table_add_col(table, heap, "NON_NULL_VALS", DATA_BINARY, 0, 0);
/* The '+ 2' below comes from the fields DB_TRX_ID, DB_ROLL_PTR */
#if DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2
#error "DICT_SYS_STATS_DIFF_VALS_FIELD != 2 + 2"
#endif
#if DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2
#error "DICT_SYS_STATS_NON_NULL_VALS_FIELD != 3 + 2"
#endif
table->id = DICT_STATS_ID;
dict_table_add_to_cache(table, heap);
dict_sys->sys_stats = table;
mem_heap_empty(heap);
index = dict_mem_index_create("SYS_STATS", "CLUST_IND",
DICT_HDR_SPACE,
DICT_UNIQUE | DICT_CLUSTERED, 2);
dict_mem_index_add_field(index, "INDEX_ID", 0);
dict_mem_index_add_field(index, "KEY_COLS", 0);
index->id = DICT_STATS_ID;
error = dict_index_add_to_cache(table, index,
mtr_read_ulint(dict_hdr
+ DICT_HDR_STATS,
MLOG_4BYTES, &mtr),
FALSE);
ut_a(error == DB_SUCCESS);
dict_add_to_cache_xtradb_sys_stats(TRUE, heap, dict_hdr, &mtr);
mem_heap_free(heap);

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2011, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -56,6 +56,8 @@ UNIV_INTERN dict_index_t* dict_ind_compact;
#include "ha_prototypes.h" /* innobase_strcasecmp(), innobase_casedn_str()*/
#include "row0upd.h"
#include "srv0start.h" /* SRV_LOG_SPACE_FIRST_ID */
#include "m_string.h"
#include "my_sys.h"
#include <ctype.h>
@ -2400,6 +2402,8 @@ dict_foreign_free(
/*==============*/
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
{
ut_a(foreign->foreign_table->n_foreign_key_checks_running == 0);
mem_heap_free(foreign->heap);
}
@ -4381,25 +4385,32 @@ dict_reload_statistics(
heap = mem_heap_create(1000);
while (index) {
mtr_t mtr;
if (table->is_corrupt) {
ut_a(srv_pass_corrupt_table);
mem_heap_free(heap);
return(FALSE);
}
size = btr_get_size(index, BTR_TOTAL_SIZE);
mtr_start(&mtr);
mtr_s_lock(dict_index_get_lock(index), &mtr);
size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
index->stat_index_size = size;
*sum_of_index_sizes += size;
size = btr_get_size(index, BTR_N_LEAF_PAGES);
size = btr_get_size(index, BTR_N_LEAF_PAGES, &mtr);
if (size == 0) {
/* The root node of the tree is a leaf */
size = 1;
}
mtr_commit(&mtr);
index->stat_n_leaf_pages = size;
/*===========================================*/
@ -4731,6 +4742,7 @@ dict_update_statistics(
(srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE
|| (srv_force_recovery < SRV_FORCE_NO_LOG_REDO
&& dict_index_is_clust(index)))) {
mtr_t mtr;
ulint size;
if (table->is_corrupt) {
@ -4739,15 +4751,24 @@ dict_update_statistics(
return;
}
size = btr_get_size(index, BTR_TOTAL_SIZE);
mtr_start(&mtr);
mtr_s_lock(dict_index_get_lock(index), &mtr);
index->stat_index_size = size;
size = btr_get_size(index, BTR_TOTAL_SIZE, &mtr);
sum_of_index_sizes += size;
if (size != ULINT_UNDEFINED) {
sum_of_index_sizes += size;
index->stat_index_size = size;
size = btr_get_size(
index, BTR_N_LEAF_PAGES, &mtr);
}
size = btr_get_size(index, BTR_N_LEAF_PAGES);
mtr_commit(&mtr);
if (size == 0) {
switch (size) {
case ULINT_UNDEFINED:
goto fake_statistics;
case 0:
/* The root node of the tree is a leaf */
size = 1;
}
@ -4764,6 +4785,7 @@ dict_update_statistics(
various means, also via secondary indexes. */
ulint i;
fake_statistics:
sum_of_index_sizes++;
index->stat_index_size = index->stat_n_leaf_pages = 1;

View file

@ -2137,8 +2137,9 @@ static
void
dict_load_foreign_cols(
/*===================*/
const char* id, /*!< in: foreign constraint id as a
null-terminated string */
const char* id, /*!< in: foreign constraint id, not
necessary '\0'-terminated */
ulint id_len, /*!< in: id length */
dict_foreign_t* foreign)/*!< in: foreign constraint object */
{
dict_table_t* sys_foreign_cols;
@ -2168,7 +2169,7 @@ dict_load_foreign_cols(
tuple = dtuple_create(foreign->heap, 1);
dfield = dtuple_get_nth_field(tuple, 0);
dfield_set_data(dfield, id, ut_strlen(id));
dfield_set_data(dfield, id, id_len);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
@ -2181,7 +2182,7 @@ dict_load_foreign_cols(
ut_a(!rec_get_deleted_flag(rec, 0));
field = rec_get_nth_field_old(rec, 0, &len);
ut_a(len == ut_strlen(id));
ut_a(len == id_len);
ut_a(ut_memcmp(id, field, len) == 0);
field = rec_get_nth_field_old(rec, 1, &len);
@ -2210,8 +2211,9 @@ static
ulint
dict_load_foreign(
/*==============*/
const char* id, /*!< in: foreign constraint id as a
null-terminated string */
const char* id, /*!< in: foreign constraint id, not
necessary '\0'-terminated */
ulint id_len, /*!< in: id length */
ibool check_charsets,
/*!< in: TRUE=check charset compatibility */
ibool check_recursive)
@ -2247,7 +2249,7 @@ dict_load_foreign(
tuple = dtuple_create(heap2, 1);
dfield = dtuple_get_nth_field(tuple, 0);
dfield_set_data(dfield, id, ut_strlen(id));
dfield_set_data(dfield, id, id_len);
dict_index_copy_types(tuple, sys_index, 1);
btr_pcur_open_on_user_rec(sys_index, tuple, PAGE_CUR_GE,
@ -2259,8 +2261,8 @@ dict_load_foreign(
/* Not found */
fprintf(stderr,
"InnoDB: Error A: cannot load foreign constraint %s\n",
id);
"InnoDB: Error A: cannot load foreign constraint "
"%.*s\n", (int) id_len, id);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@ -2272,11 +2274,11 @@ dict_load_foreign(
field = rec_get_nth_field_old(rec, 0, &len);
/* Check if the id in record is the searched one */
if (len != ut_strlen(id) || ut_memcmp(id, field, len) != 0) {
if (len != id_len || ut_memcmp(id, field, len) != 0) {
fprintf(stderr,
"InnoDB: Error B: cannot load foreign constraint %s\n",
id);
"InnoDB: Error B: cannot load foreign constraint "
"%.*s\n", (int) id_len, id);
btr_pcur_close(&pcur);
mtr_commit(&mtr);
@ -2302,7 +2304,7 @@ dict_load_foreign(
foreign->type = (unsigned int) (n_fields_and_type >> 24);
foreign->n_fields = (unsigned int) (n_fields_and_type & 0x3FFUL);
foreign->id = mem_heap_strdup(foreign->heap, id);
foreign->id = mem_heap_strdupl(foreign->heap, id, id_len);
field = rec_get_nth_field_old(rec, 3, &len);
@ -2318,7 +2320,7 @@ dict_load_foreign(
btr_pcur_close(&pcur);
mtr_commit(&mtr);
dict_load_foreign_cols(id, foreign);
dict_load_foreign_cols(id, id_len, foreign);
ref_table = dict_table_check_if_in_cache_low(
foreign->referenced_table_name_lookup);
@ -2397,8 +2399,8 @@ dict_load_foreigns(
ibool check_charsets) /*!< in: TRUE=check charset
compatibility */
{
char tuple_buf[DTUPLE_EST_ALLOC(1)];
btr_pcur_t pcur;
mem_heap_t* heap;
dtuple_t* tuple;
dfield_t* dfield;
dict_index_t* sec_index;
@ -2406,7 +2408,6 @@ dict_load_foreigns(
const rec_t* rec;
const byte* field;
ulint len;
char* id ;
ulint err;
mtr_t mtr;
@ -2433,9 +2434,8 @@ dict_load_foreigns(
sec_index = dict_table_get_next_index(
dict_table_get_first_index(sys_foreign));
start_load:
heap = mem_heap_create(256);
tuple = dtuple_create(heap, 1);
tuple = dtuple_create_from_mem(tuple_buf, sizeof(tuple_buf), 1);
dfield = dtuple_get_nth_field(tuple, 0);
dfield_set_data(dfield, table_name, ut_strlen(table_name));
@ -2489,7 +2489,6 @@ loop:
/* Now we get a foreign key constraint id */
field = rec_get_nth_field_old(rec, 1, &len);
id = mem_heap_strdupl(heap, (char*) field, len);
btr_pcur_store_position(&pcur, &mtr);
@ -2497,11 +2496,11 @@ loop:
/* Load the foreign constraint definition to the dictionary cache */
err = dict_load_foreign(id, check_charsets, check_recursive);
err = dict_load_foreign((char*) field, len, check_charsets,
check_recursive);
if (err != DB_SUCCESS) {
btr_pcur_close(&pcur);
mem_heap_free(heap);
return(err);
}
@ -2517,7 +2516,6 @@ next_rec:
load_next_index:
btr_pcur_close(&pcur);
mtr_commit(&mtr);
mem_heap_free(heap);
sec_index = dict_table_get_next_index(sec_index);

View file

@ -193,7 +193,7 @@ struct fil_space_struct {
.ibd file of tablespace and want to
stop temporarily posting of new i/o
requests on the file */
ibool stop_ibuf_merges;
ibool stop_new_ops;
/*!< we set this TRUE when we start
deleting a single-table tablespace */
ibool is_being_deleted;
@ -218,12 +218,13 @@ struct fil_space_struct {
ulint n_pending_flushes; /*!< this is positive when flushing
the tablespace to disk; dropping of the
tablespace is forbidden if this is positive */
ulint n_pending_ibuf_merges;/*!< this is positive
when merging insert buffer entries to
a page so that we may need to access
the ibuf bitmap page in the
tablespade: dropping of the tablespace
is forbidden if this is positive */
ulint n_pending_ops;/*!< this is positive when we
have pending operations against this
tablespace. The pending operations can
be ibuf merges or lock validation code
trying to read a block.
Dropping of the tablespace is forbidden
if this is positive */
hash_node_t hash; /*!< hash chain node */
hash_node_t name_hash;/*!< hash chain the name_hash table */
#ifndef UNIV_HOTBACKUP
@ -974,11 +975,6 @@ retry:
return;
}
if (fil_system->n_open < fil_system->max_n_open) {
return;
}
space = fil_space_get_by_id(space_id);
if (space != NULL && space->stop_ios) {
@ -995,6 +991,25 @@ retry:
mutex_exit(&fil_system->mutex);
#ifndef UNIV_HOTBACKUP
/* Wake the i/o-handler threads to make sure pending
i/o's are performed */
os_aio_simulated_wake_handler_threads();
/* The sleep here is just to give IO helper threads a
bit of time to do some work. It is not required that
all IO related to the tablespace being renamed must
be flushed here as we do fil_flush() in
fil_rename_tablespace() as well. */
os_thread_sleep(20000);
#endif /* UNIV_HOTBACKUP */
/* Flush tablespaces so that we can close modified
files in the LRU list */
fil_flush_file_spaces(FIL_TABLESPACE);
os_thread_sleep(20000);
count2++;
@ -1002,6 +1017,11 @@ retry:
goto retry;
}
if (fil_system->n_open < fil_system->max_n_open) {
return;
}
/* If the file is already open, no need to do anything; if the space
does not exist, we handle the situation in the function which called
this function */
@ -1274,7 +1294,7 @@ try_again:
}
space->stop_ios = FALSE;
space->stop_ibuf_merges = FALSE;
space->stop_new_ops = FALSE;
space->is_being_deleted = FALSE;
space->purpose = purpose;
space->size = 0;
@ -1283,7 +1303,7 @@ try_again:
space->n_reserved_extents = 0;
space->n_pending_flushes = 0;
space->n_pending_ibuf_merges = 0;
space->n_pending_ops = 0;
UT_LIST_INIT(space->chain);
space->magic_n = FIL_SPACE_MAGIC_N;
@ -1896,13 +1916,12 @@ fil_read_first_page(
#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
Increments the count of pending insert buffer page merges, if space is not
being deleted.
@return TRUE if being deleted, and ibuf merges should be skipped */
Increments the count of pending operation, if space is not being deleted.
@return TRUE if being deleted, and operation should be skipped */
UNIV_INTERN
ibool
fil_inc_pending_ibuf_merges(
/*========================*/
fil_inc_pending_ops(
/*================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
@ -1918,13 +1937,13 @@ fil_inc_pending_ibuf_merges(
(ulong) id);
}
if (space == NULL || space->stop_ibuf_merges) {
if (space == NULL || space->stop_new_ops) {
mutex_exit(&fil_system->mutex);
return(TRUE);
}
space->n_pending_ibuf_merges++;
space->n_pending_ops++;
mutex_exit(&fil_system->mutex);
@ -1932,11 +1951,11 @@ fil_inc_pending_ibuf_merges(
}
/*******************************************************************//**
Decrements the count of pending insert buffer page merges. */
Decrements the count of pending operations. */
UNIV_INTERN
void
fil_decr_pending_ibuf_merges(
/*=========================*/
fil_decr_pending_ops(
/*=================*/
ulint id) /*!< in: space id */
{
fil_space_t* space;
@ -1947,13 +1966,13 @@ fil_decr_pending_ibuf_merges(
if (space == NULL) {
fprintf(stderr,
"InnoDB: Error: decrementing ibuf merge of a"
" dropped tablespace %lu\n",
"InnoDB: Error: decrementing pending operation"
" of a dropped tablespace %lu\n",
(ulong) id);
}
if (space != NULL) {
space->n_pending_ibuf_merges--;
space->n_pending_ops--;
}
mutex_exit(&fil_system->mutex);
@ -2164,7 +2183,7 @@ fil_op_log_parse_or_replay(
switch (type) {
case MLOG_FILE_DELETE:
if (fil_tablespace_exists_in_mem(space_id)) {
ut_a(fil_delete_tablespace(space_id));
ut_a(fil_delete_tablespace(space_id, TRUE));
}
break;
@ -2234,7 +2253,9 @@ UNIV_INTERN
ibool
fil_delete_tablespace(
/*==================*/
ulint id) /*!< in: space id */
ulint id, /*!< in: space id */
ibool evict_all) /*!< in: TRUE if we want all pages
evicted from LRU. */
{
ibool success;
fil_space_t* space;
@ -2243,15 +2264,15 @@ fil_delete_tablespace(
char* path;
ut_a(id != 0);
stop_ibuf_merges:
stop_new_ops:
mutex_enter(&fil_system->mutex);
space = fil_space_get_by_id(id);
if (space != NULL) {
space->stop_ibuf_merges = TRUE;
space->stop_new_ops = TRUE;
if (space->n_pending_ibuf_merges == 0) {
if (space->n_pending_ops == 0) {
mutex_exit(&fil_system->mutex);
count = 0;
@ -2265,9 +2286,10 @@ stop_ibuf_merges:
ut_print_filename(stderr, space->name);
fprintf(stderr, ",\n"
"InnoDB: but there are %lu pending"
" ibuf merges on it.\n"
" operations (most likely ibuf merges)"
" on it.\n"
"InnoDB: Loop %lu.\n",
(ulong) space->n_pending_ibuf_merges,
(ulong) space->n_pending_ops,
(ulong) count);
}
@ -2276,7 +2298,7 @@ stop_ibuf_merges:
os_thread_sleep(20000);
count++;
goto stop_ibuf_merges;
goto stop_new_ops;
}
}
@ -2302,7 +2324,7 @@ try_again:
}
ut_a(space);
ut_a(space->n_pending_ibuf_merges == 0);
ut_a(space->n_pending_ops == 0);
space->is_being_deleted = TRUE;
@ -2358,7 +2380,11 @@ try_again:
if (srv_lazy_drop_table) {
buf_LRU_mark_space_was_deleted(id);
} else {
buf_LRU_invalidate_tablespace(id);
buf_LRU_flush_or_remove_pages(
id, evict_all
? BUF_REMOVE_ALL_NO_WRITE
: BUF_REMOVE_FLUSH_NO_WRITE);
}
#endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */
@ -2447,7 +2473,7 @@ fil_discard_tablespace(
{
ibool success;
success = fil_delete_tablespace(id);
success = fil_delete_tablespace(id, TRUE);
if (!success) {
fprintf(stderr,
@ -2579,7 +2605,7 @@ fil_rename_tablespace(
retry:
count++;
if (count > 1000) {
if (!(count % 1000)) {
ut_print_timestamp(stderr);
fputs(" InnoDB: Warning: problems renaming ", stderr);
ut_print_filename(stderr, old_name);
@ -3905,7 +3931,7 @@ convert_err_exit:
level = btr_page_get_level(page, &mtr);
new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, &mtr);
new_block = btr_page_alloc(index, 0, FSP_NO_DIR, level, &mtr, &mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, index, level, &mtr);
@ -3953,7 +3979,7 @@ convert_err_exit:
split_rec = page_get_middle_rec(page);
new_block = btr_page_alloc(index, page_no + 1, FSP_UP,
btr_page_get_level(page, &mtr), &mtr);
btr_page_get_level(page, &mtr), &mtr, &mtr);
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
btr_page_create(new_block, new_page_zip, index,

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1995, 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
@ -248,28 +248,38 @@ fsp_fill_free_list(
descriptor page and ibuf bitmap page;
then we do not allocate more extents */
ulint space, /*!< in: space */
fsp_header_t* header, /*!< in: space header */
mtr_t* mtr); /*!< in: mtr */
fsp_header_t* header, /*!< in/out: space header */
mtr_t* mtr) /*!< in/out: mini-transaction */
__attribute__((nonnull));
/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
@return the allocated page number, FIL_NULL if no page could be allocated */
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
static
ulint
buf_block_t*
fseg_alloc_free_page_low(
/*=====================*/
ulint space, /*!< in: space */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
fseg_inode_t* seg_inode, /*!< in: segment inode */
ulint hint, /*!< in: hint of which page would be desirable */
fseg_inode_t* seg_inode, /*!< in/out: segment inode */
ulint hint, /*!< in: hint of which page would be
desirable */
byte direction, /*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
mtr_t* mtr); /*!< in: mtr handle */
mtr_t* mtr, /*!< in/out: mini-transaction */
mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
in which the page should be initialized.
If init_mtr!=mtr, but the page is already
latched in mtr, do not initialize the page. */
__attribute__((warn_unused_result, nonnull));
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
@ -639,23 +649,22 @@ xdes_calc_descriptor_index(
/********************************************************************//**
Gets pointer to a the extent descriptor of a page. The page where the extent
descriptor resides is x-locked. If the page offset is equal to the free limit
of the space, adds new extents from above the free limit to the space free
list, if not free limit == space size. This adding is necessary to make the
descriptor defined, as they are uninitialized above the free limit.
descriptor resides is x-locked. This function no longer extends the data
file.
@return pointer to the extent descriptor, NULL if the page does not
exist in the space or if the offset exceeds the free limit */
UNIV_INLINE
exist in the space or if the offset is >= the free limit */
UNIV_INLINE __attribute__((nonnull, warn_unused_result))
xdes_t*
xdes_get_descriptor_with_space_hdr(
/*===============================*/
fsp_header_t* sp_header,/*!< in/out: space header, x-latched */
ulint space, /*!< in: space id */
ulint offset, /*!< in: page offset;
if equal to the free limit,
we try to add new extents to
the space free list */
mtr_t* mtr) /*!< in: mtr handle */
fsp_header_t* sp_header, /*!< in/out: space header, x-latched
in mtr */
ulint space, /*!< in: space id */
ulint offset, /*!< in: page offset; if equal
to the free limit, we try to
add new extents to the space
free list */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint limit;
ulint size;
@ -663,11 +672,9 @@ xdes_get_descriptor_with_space_hdr(
ulint descr_page_no;
page_t* descr_page;
ut_ad(mtr);
ut_ad(mtr_memo_contains(mtr, fil_space_get_latch(space, NULL),
MTR_MEMO_X_LOCK));
ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_S_FIX)
|| mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
ut_ad(mtr_memo_contains_page(mtr, sp_header, MTR_MEMO_PAGE_X_FIX));
ut_ad(page_offset(sp_header) == FSP_HEADER_OFFSET);
/* Read free limit and space size */
limit = mach_read_from_4(sp_header + FSP_FREE_LIMIT);
@ -704,8 +711,8 @@ Gets pointer to a the extent descriptor of a page. The page where the extent
descriptor resides is x-locked. This function no longer extends the data
file.
@return pointer to the extent descriptor, NULL if the page does not
exist in the space or if the offset is >= the free limit */
static
exist in the space or if the offset exceeds the free limit */
static __attribute__((nonnull, warn_unused_result))
xdes_t*
xdes_get_descriptor(
/*================*/
@ -714,7 +721,7 @@ xdes_get_descriptor(
or 0 for uncompressed pages */
ulint offset, /*!< in: page offset; if equal to the free limit,
we try to add new extents to the space free list */
mtr_t* mtr) /*!< in: mtr handle */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
buf_block_t* block;
fsp_header_t* sp_header;
@ -1098,14 +1105,14 @@ fsp_header_get_tablespace_size(void)
Tries to extend a single-table tablespace so that a page would fit in the
data file.
@return TRUE if success */
static
static __attribute__((nonnull, warn_unused_result))
ibool
fsp_try_extend_data_file_with_pages(
/*================================*/
ulint space, /*!< in: space */
ulint page_no, /*!< in: page number */
fsp_header_t* header, /*!< in: space header */
mtr_t* mtr) /*!< in: mtr */
fsp_header_t* header, /*!< in/out: space header */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ibool success;
ulint actual_size;
@ -1130,7 +1137,7 @@ fsp_try_extend_data_file_with_pages(
/***********************************************************************//**
Tries to extend the last data file of a tablespace if it is auto-extending.
@return FALSE if not auto-extending */
static
static __attribute__((nonnull))
ibool
fsp_try_extend_data_file(
/*=====================*/
@ -1140,8 +1147,8 @@ fsp_try_extend_data_file(
the actual file size rounded down to
megabyte */
ulint space, /*!< in: space */
fsp_header_t* header, /*!< in: space header */
mtr_t* mtr) /*!< in: mtr */
fsp_header_t* header, /*!< in/out: space header */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint size;
ulint zip_size;
@ -1277,7 +1284,7 @@ fsp_fill_free_list(
then we do not allocate more extents */
ulint space, /*!< in: space */
fsp_header_t* header, /*!< in/out: space header */
mtr_t* mtr) /*!< in: mtr */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint limit;
ulint size;
@ -1476,29 +1483,120 @@ fsp_alloc_free_extent(
}
/**********************************************************************//**
Allocates a single free page from a space. The page is marked as used.
@return the page offset, FIL_NULL if no page could be allocated */
Allocates a single free page from a space. */
static __attribute__((nonnull))
void
fsp_alloc_from_free_frag(
/*=====================*/
fsp_header_t* header, /*!< in/out: tablespace header */
xdes_t* descr, /*!< in/out: extent descriptor */
ulint bit, /*!< in: slot to allocate in the extent */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
ulint frag_n_used;
ut_ad(xdes_get_state(descr, mtr) == XDES_FREE_FRAG);
ut_a(xdes_get_bit(descr, XDES_FREE_BIT, bit, mtr));
xdes_set_bit(descr, XDES_FREE_BIT, bit, FALSE, mtr);
/* Update the FRAG_N_USED field */
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
mtr);
frag_n_used++;
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
mtr);
if (xdes_is_full(descr, mtr)) {
/* The fragment is full: move it to another list */
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
mtr);
xdes_set_state(descr, XDES_FULL_FRAG, mtr);
flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
mtr);
mlog_write_ulint(header + FSP_FRAG_N_USED,
frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
mtr);
}
}
/**********************************************************************//**
Gets a buffer block for an allocated page.
NOTE: If init_mtr != mtr, the block will only be initialized if it was
not previously x-latched. It is assumed that the block has been
x-latched only by mtr, and freed in mtr in that case.
@return block, initialized if init_mtr==mtr
or rw_lock_x_lock_count(&block->lock) == 1 */
static
ulint
buf_block_t*
fsp_page_create(
/*============*/
ulint space, /*!< in: space id of the allocated page */
ulint zip_size, /*!< in: compressed page size in bytes
or 0 for uncompressed pages */
ulint page_no, /*!< in: page number of the allocated page */
mtr_t* mtr, /*!< in: mini-transaction of the allocation */
mtr_t* init_mtr) /*!< in: mini-transaction for initializing
the page */
{
buf_block_t* block
= buf_page_create(space, page_no, zip_size, init_mtr);
#ifdef UNIV_SYNC_DEBUG
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX)
== rw_lock_own(&block->lock, RW_LOCK_EX));
#endif /* UNIV_SYNC_DEBUG */
/* Mimic buf_page_get(), but avoid the buf_pool->page_hash lookup. */
rw_lock_x_lock(&block->lock);
mutex_enter(&block->mutex);
buf_block_buf_fix_inc(block, __FILE__, __LINE__);
mutex_exit(&block->mutex);
mtr_memo_push(init_mtr, block, MTR_MEMO_PAGE_X_FIX);
if (init_mtr == mtr
|| rw_lock_get_x_lock_count(&block->lock) == 1) {
/* Initialize the page, unless it was already
X-latched in mtr. (In this case, we would want to
allocate another page that has not been freed in mtr.) */
ut_ad(init_mtr == mtr
|| !mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
fsp_init_file_page(block, init_mtr);
}
return(block);
}
/**********************************************************************//**
Allocates a single free page from a space. The page is marked as used.
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
static __attribute__((nonnull, warn_unused_result))
buf_block_t*
fsp_alloc_free_page(
/*================*/
ulint space, /*!< in: space id */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
ulint hint, /*!< in: hint of which page would be desirable */
mtr_t* mtr) /*!< in: mtr handle */
mtr_t* mtr, /*!< in/out: mini-transaction */
mtr_t* init_mtr)/*!< in/out: mini-transaction in which the
page should be initialized
(may be the same as mtr) */
{
fsp_header_t* header;
fil_addr_t first;
xdes_t* descr;
buf_block_t* block;
ulint free;
ulint frag_n_used;
ulint page_no;
ulint space_size;
ibool success;
ut_ad(mtr);
ut_ad(init_mtr);
header = fsp_get_space_header(space, zip_size, mtr);
@ -1525,7 +1623,7 @@ fsp_alloc_free_page(
if (descr == NULL) {
/* No free space left */
return(FIL_NULL);
return(NULL);
}
xdes_set_state(descr, XDES_FREE_FRAG, mtr);
@ -1570,50 +1668,18 @@ fsp_alloc_free_page(
" space size %lu. Page no %lu.\n",
(ulong) space, (ulong) space_size,
(ulong) page_no);
return(FIL_NULL);
return(NULL);
}
success = fsp_try_extend_data_file_with_pages(space, page_no,
header, mtr);
if (!success) {
if (!fsp_try_extend_data_file_with_pages(space, page_no,
header, mtr)) {
/* No disk space left */
return(FIL_NULL);
return(NULL);
}
}
xdes_set_bit(descr, XDES_FREE_BIT, free, FALSE, mtr);
fsp_alloc_from_free_frag(header, descr, free, mtr);
/* Update the FRAG_N_USED field */
frag_n_used = mtr_read_ulint(header + FSP_FRAG_N_USED, MLOG_4BYTES,
mtr);
frag_n_used++;
mlog_write_ulint(header + FSP_FRAG_N_USED, frag_n_used, MLOG_4BYTES,
mtr);
if (xdes_is_full(descr, mtr)) {
/* The fragment is full: move it to another list */
flst_remove(header + FSP_FREE_FRAG, descr + XDES_FLST_NODE,
mtr);
xdes_set_state(descr, XDES_FULL_FRAG, mtr);
flst_add_last(header + FSP_FULL_FRAG, descr + XDES_FLST_NODE,
mtr);
mlog_write_ulint(header + FSP_FRAG_N_USED,
frag_n_used - FSP_EXTENT_SIZE, MLOG_4BYTES,
mtr);
}
/* Initialize the allocated page to the buffer pool, so that it can
be obtained immediately with buf_page_get without need for a disk
read. */
buf_page_create(space, page_no, zip_size, mtr);
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
/* Prior contents of the page should be ignored */
fsp_init_file_page(block, mtr);
return(page_no);
return(fsp_page_create(space, zip_size, page_no, mtr, init_mtr));
}
/**********************************************************************//**
@ -1652,6 +1718,9 @@ fsp_free_page(
fputs("InnoDB: Dump of descriptor: ", stderr);
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
putc('\n', stderr);
/* Crash in debug version, so that we get a core dump
of this corruption. */
ut_ad(0);
if (state == XDES_FREE) {
/* We put here some fault tolerance: if the page
@ -1670,6 +1739,9 @@ fsp_free_page(
"InnoDB: Dump of descriptor: ", (ulong) page);
ut_print_buf(stderr, ((byte*)descr) - 50, 200);
putc('\n', stderr);
/* Crash in debug version, so that we get a core dump
of this corruption. */
ut_ad(0);
/* We put here some fault tolerance: if the page
is already free, return without doing anything! */
@ -1704,6 +1776,8 @@ fsp_free_page(
mtr);
fsp_free_extent(space, zip_size, page, mtr);
}
mtr->n_freed_pages++;
}
/**********************************************************************//**
@ -1841,7 +1915,6 @@ fsp_alloc_seg_inode_page(
fseg_inode_t* inode;
buf_block_t* block;
page_t* page;
ulint page_no;
ulint space;
ulint zip_size;
ulint i;
@ -1852,15 +1925,15 @@ fsp_alloc_seg_inode_page(
zip_size = dict_table_flags_to_zip_size(
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
page_no = fsp_alloc_free_page(space, zip_size, 0, mtr);
block = fsp_alloc_free_page(space, zip_size, 0, mtr, mtr);
if (page_no == FIL_NULL) {
if (block == NULL) {
return(FALSE);
}
block = buf_page_get(space, zip_size, page_no, RW_X_LATCH, mtr);
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
block->check_index_page_at_flush = FALSE;
@ -2273,19 +2346,20 @@ fseg_create_general(
}
if (page == 0) {
page = fseg_alloc_free_page_low(space, zip_size,
inode, 0, FSP_UP, mtr);
block = fseg_alloc_free_page_low(space, zip_size,
inode, 0, FSP_UP, mtr, mtr);
if (page == FIL_NULL) {
if (block == NULL) {
fsp_free_seg_inode(space, zip_size, inode, mtr);
goto funct_exit;
}
block = buf_page_get(space, zip_size, page, RW_X_LATCH, mtr);
ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
header = byte_offset + buf_block_get_frame(block);
mlog_write_ulint(header - byte_offset + FIL_PAGE_TYPE,
mlog_write_ulint(buf_block_get_frame(block) + FIL_PAGE_TYPE,
FIL_PAGE_TYPE_SYS, MLOG_2BYTES, mtr);
}
@ -2462,8 +2536,10 @@ fseg_fill_free_list(
Allocates a free extent for the segment: looks first in the free list of the
segment, then tries to allocate from the space free list. NOTE that the extent
returned still resides in the segment free list, it is not yet taken off it!
@return allocated extent, still placed in the segment free list, NULL
if could not be allocated */
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
static
xdes_t*
fseg_alloc_free_extent(
@ -2515,22 +2591,30 @@ fseg_alloc_free_extent(
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
@return the allocated page number, FIL_NULL if no page could be allocated */
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
static
ulint
buf_block_t*
fseg_alloc_free_page_low(
/*=====================*/
ulint space, /*!< in: space */
ulint zip_size,/*!< in: compressed page size in bytes
or 0 for uncompressed pages */
fseg_inode_t* seg_inode, /*!< in: segment inode */
ulint hint, /*!< in: hint of which page would be desirable */
fseg_inode_t* seg_inode, /*!< in/out: segment inode */
ulint hint, /*!< in: hint of which page would be
desirable */
byte direction, /*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
mtr_t* mtr) /*!< in: mtr handle */
mtr_t* mtr, /*!< in/out: mini-transaction */
mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
in which the page should be initialized.
If init_mtr!=mtr, but the page is already
latched in mtr, do not initialize the page. */
{
fsp_header_t* space_header;
ulint space_size;
@ -2541,7 +2625,6 @@ fseg_alloc_free_page_low(
ulint ret_page; /*!< the allocated page offset, FIL_NULL
if could not be allocated */
xdes_t* ret_descr; /*!< the extent of the allocated page */
ibool frag_page_allocated = FALSE;
ibool success;
ulint n;
@ -2563,6 +2646,7 @@ fseg_alloc_free_page_low(
if (descr == NULL) {
/* Hint outside space or too high above free limit: reset
hint */
/* The file space header page is always allocated. */
hint = 0;
descr = xdes_get_descriptor(space, zip_size, hint, mtr);
}
@ -2573,15 +2657,19 @@ fseg_alloc_free_page_low(
&& mach_read_from_8(descr + XDES_ID) == seg_id
&& (xdes_get_bit(descr, XDES_FREE_BIT,
hint % FSP_EXTENT_SIZE, mtr) == TRUE)) {
take_hinted_page:
/* 1. We can take the hinted page
=================================*/
ret_descr = descr;
ret_page = hint;
/* Skip the check for extending the tablespace. If the
page hint were not within the size of the tablespace,
we would have got (descr == NULL) above and reset the hint. */
goto got_hinted_page;
/*-----------------------------------------------------------*/
} else if ((xdes_get_state(descr, mtr) == XDES_FREE)
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
&& (used >= FSEG_FRAG_LIMIT)) {
} else if (xdes_get_state(descr, mtr) == XDES_FREE
&& reserved - used < reserved / FSEG_FILLFACTOR
&& used >= FSEG_FRAG_LIMIT) {
/* 2. We allocate the free extent from space and can take
=========================================================
@ -2599,7 +2687,7 @@ fseg_alloc_free_page_low(
/* Try to fill the segment free list */
fseg_fill_free_list(seg_inode, space, zip_size,
hint + FSP_EXTENT_SIZE, mtr);
ret_page = hint;
goto take_hinted_page;
/*-----------------------------------------------------------*/
} else if ((direction != FSP_NO_DIR)
&& ((reserved - used) < reserved / FSEG_FILLFACTOR)
@ -2647,7 +2735,7 @@ fseg_alloc_free_page_low(
first = flst_get_first(seg_inode + FSEG_FREE, mtr);
} else {
ut_error;
return(FIL_NULL);
return(NULL);
}
ret_descr = xdes_lst_get_descriptor(space, zip_size,
@ -2659,20 +2747,23 @@ fseg_alloc_free_page_low(
} else if (used < FSEG_FRAG_LIMIT) {
/* 6. We allocate an individual page from the space
===================================================*/
ret_page = fsp_alloc_free_page(space, zip_size, hint, mtr);
ret_descr = NULL;
buf_block_t* block = fsp_alloc_free_page(
space, zip_size, hint, mtr, init_mtr);
frag_page_allocated = TRUE;
if (ret_page != FIL_NULL) {
if (block != NULL) {
/* Put the page in the fragment page array of the
segment */
n = fseg_find_free_frag_page_slot(seg_inode, mtr);
ut_a(n != FIL_NULL);
ut_a(n != ULINT_UNDEFINED);
fseg_set_nth_frag_page_no(seg_inode, n, ret_page,
mtr);
fseg_set_nth_frag_page_no(
seg_inode, n, buf_block_get_page_no(block),
mtr);
}
/* fsp_alloc_free_page() invoked fsp_init_file_page()
already. */
return(block);
/*-----------------------------------------------------------*/
} else {
/* 7. We allocate a new extent and take its first page
@ -2690,7 +2781,7 @@ fseg_alloc_free_page_low(
if (ret_page == FIL_NULL) {
/* Page could not be allocated */
return(FIL_NULL);
return(NULL);
}
if (space != 0) {
@ -2708,38 +2799,22 @@ fseg_alloc_free_page_low(
" the space size %lu. Page no %lu.\n",
(ulong) space, (ulong) space_size,
(ulong) ret_page);
return(FIL_NULL);
return(NULL);
}
success = fsp_try_extend_data_file_with_pages(
space, ret_page, space_header, mtr);
if (!success) {
/* No disk space left */
return(FIL_NULL);
return(NULL);
}
}
}
if (!frag_page_allocated) {
/* Initialize the allocated page to buffer pool, so that it
can be obtained immediately with buf_page_get without need
for a disk read */
buf_block_t* block;
ulint zip_size = dict_table_flags_to_zip_size(
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
block = buf_page_create(space, ret_page, zip_size, mtr);
buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
if (UNIV_UNLIKELY(block != buf_page_get(space, zip_size,
ret_page, RW_X_LATCH,
mtr))) {
ut_error;
}
/* The prior contents of the page should be ignored */
fsp_init_file_page(block, mtr);
got_hinted_page:
/* ret_descr == NULL if the block was allocated from free_frag
(XDES_FREE_FRAG) */
if (ret_descr != NULL) {
/* At this point we know the extent and the page offset.
The extent is still in the appropriate list (FSEG_NOT_FULL
or FSEG_FREE), and the page is not yet marked as used. */
@ -2752,22 +2827,28 @@ fseg_alloc_free_page_low(
fseg_mark_page_used(seg_inode, ret_page, ret_descr, mtr);
}
buf_reset_check_index_page_at_flush(space, ret_page);
return(ret_page);
return(fsp_page_create(
space, dict_table_flags_to_zip_size(
mach_read_from_4(FSP_SPACE_FLAGS
+ space_header)),
ret_page, mtr, init_mtr));
}
/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
@return allocated page offset, FIL_NULL if no page could be allocated */
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
UNIV_INTERN
ulint
buf_block_t*
fseg_alloc_free_page_general(
/*=========================*/
fseg_header_t* seg_header,/*!< in: segment header */
ulint hint, /*!< in: hint of which page would be desirable */
fseg_header_t* seg_header,/*!< in/out: segment header */
ulint hint, /*!< in: hint of which page would be
desirable */
byte direction,/*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
@ -2778,15 +2859,18 @@ fseg_alloc_free_page_general(
with fsp_reserve_free_extents, then there
is no need to do the check for this individual
page */
mtr_t* mtr) /*!< in: mtr handle */
mtr_t* mtr, /*!< in/out: mini-transaction handle */
mtr_t* init_mtr)/*!< in/out: mtr or another mini-transaction
in which the page should be initialized.
If init_mtr!=mtr, but the page is already
latched in mtr, do not initialize the page. */
{
fseg_inode_t* inode;
ulint space;
ulint flags;
ulint zip_size;
rw_lock_t* latch;
ibool success;
ulint page_no;
buf_block_t* block;
ulint n_reserved;
space = page_get_space_id(page_align(seg_header));
@ -2811,43 +2895,20 @@ fseg_alloc_free_page_general(
inode = fseg_inode_get(seg_header, space, zip_size, mtr);
if (!has_done_reservation) {
success = fsp_reserve_free_extents(&n_reserved, space, 2,
FSP_NORMAL, mtr);
if (!success) {
return(FIL_NULL);
}
if (!has_done_reservation
&& !fsp_reserve_free_extents(&n_reserved, space, 2,
FSP_NORMAL, mtr)) {
return(NULL);
}
page_no = fseg_alloc_free_page_low(space, zip_size,
inode, hint, direction, mtr);
block = fseg_alloc_free_page_low(space, zip_size,
inode, hint, direction,
mtr, init_mtr);
if (!has_done_reservation) {
fil_space_release_free_extents(space, n_reserved);
}
return(page_no);
}
/**********************************************************************//**
Allocates a single free page from a segment. This function implements
the intelligent allocation strategy which tries to minimize file space
fragmentation.
@return allocated page offset, FIL_NULL if no page could be allocated */
UNIV_INTERN
ulint
fseg_alloc_free_page(
/*=================*/
fseg_header_t* seg_header,/*!< in: segment header */
ulint hint, /*!< in: hint of which page would be desirable */
byte direction,/*!< in: if the new page is needed because
of an index page split, and records are
inserted there in order, into which
direction they go alphabetically: FSP_DOWN,
FSP_UP, FSP_NO_DIR */
mtr_t* mtr) /*!< in: mtr handle */
{
return(fseg_alloc_free_page_general(seg_header, hint, direction,
FALSE, mtr));
return(block);
}
/**********************************************************************//**
@ -3358,6 +3419,8 @@ crash:
descr + XDES_FLST_NODE, mtr);
fsp_free_extent(space, zip_size, page, mtr);
}
mtr->n_freed_pages++;
}
/**********************************************************************//**

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2000, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2000, 2012, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, 2009 Google Inc.
Copyright (c) 2009, Percona Inc.
@ -26,8 +26,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -194,6 +194,9 @@ static my_bool innobase_create_status_file = FALSE;
static my_bool innobase_stats_on_metadata = TRUE;
static my_bool innobase_large_prefix = FALSE;
static my_bool innobase_use_sys_stats_table = FALSE;
#ifdef UNIV_DEBUG
static ulong innobase_sys_stats_root_page = 0;
#endif
static my_bool innobase_buffer_pool_shm_checksum = TRUE;
static uint innobase_buffer_pool_shm_key = 0;
@ -1169,6 +1172,9 @@ convert_error_code_to_mysql(
case DB_OUT_OF_FILE_SPACE:
return(HA_ERR_RECORD_FILE_FULL);
case DB_TABLE_IN_FK_CHECK:
return(HA_ERR_TABLE_IN_FK_CHECK);
case DB_TABLE_IS_BEING_USED:
return(HA_ERR_WRONG_COMMAND);
@ -2718,6 +2724,10 @@ mem_free_and_error:
srv_use_sys_stats_table = (ibool) innobase_use_sys_stats_table;
#ifdef UNIV_DEBUG
srv_sys_stats_root_page = innobase_sys_stats_root_page;
#endif
/* -------------- Log files ---------------------------*/
/* The default dir for log files is the datadir of MySQL */
@ -3815,52 +3825,140 @@ ha_innobase::primary_key_is_clustered()
return(true);
}
/** Always normalize table name to lower case on Windows */
#ifdef __WIN__
#define normalize_table_name(norm_name, name) \
normalize_table_name_low(norm_name, name, TRUE)
#else
#define normalize_table_name(norm_name, name) \
normalize_table_name_low(norm_name, name, FALSE)
#endif /* __WIN__ */
/*****************************************************************//**
Normalizes a table name string. A normalized name consists of the
database name catenated to '/' and table name. An example:
test/mytable. On Windows normalization puts both the database name and the
table name always to lower case. */
table name always to lower case if "set_lower_case" is set to TRUE. */
static
void
normalize_table_name(
/*=================*/
normalize_table_name_low(
/*=====================*/
char* norm_name, /*!< out: normalized name as a
null-terminated string */
const char* name) /*!< in: table name string */
const char* name, /*!< in: table name string */
ibool set_lower_case) /*!< in: TRUE if we want to set
name to lower case */
{
char* name_ptr;
char* db_ptr;
ulint db_len;
char* ptr;
/* Scan name from the end */
ptr = strend(name)-1;
ptr = strend(name) - 1;
/* seek to the last path separator */
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
}
name_ptr = ptr + 1;
DBUG_ASSERT(ptr > name);
/* skip any number of path separators */
while (ptr >= name && (*ptr == '\\' || *ptr == '/')) {
ptr--;
}
ptr--;
DBUG_ASSERT(ptr >= name);
/* seek to the last but one path separator or one char before
the beginning of name */
db_len = 0;
while (ptr >= name && *ptr != '\\' && *ptr != '/') {
ptr--;
db_len++;
}
db_ptr = ptr + 1;
memcpy(norm_name, db_ptr, strlen(name) + 1 - (db_ptr - name));
memcpy(norm_name, db_ptr, db_len);
norm_name[name_ptr - db_ptr - 1] = '/';
norm_name[db_len] = '/';
#ifdef __WIN__
innobase_casedn_str(norm_name);
#endif
memcpy(norm_name + db_len + 1, name_ptr, strlen(name_ptr) + 1);
if (set_lower_case) {
innobase_casedn_str(norm_name);
}
}
#if !defined(DBUG_OFF)
/*********************************************************************
Test normalize_table_name_low(). */
static
void
test_normalize_table_name_low()
/*===========================*/
{
char norm_name[128];
const char* test_data[][2] = {
/* input, expected result */
{"./mysqltest/t1", "mysqltest/t1"},
{"./test/#sql-842b_2", "test/#sql-842b_2"},
{"./test/#sql-85a3_10", "test/#sql-85a3_10"},
{"./test/#sql2-842b-2", "test/#sql2-842b-2"},
{"./test/bug29807", "test/bug29807"},
{"./test/foo", "test/foo"},
{"./test/innodb_bug52663", "test/innodb_bug52663"},
{"./test/t", "test/t"},
{"./test/t1", "test/t1"},
{"./test/t10", "test/t10"},
{"/a/b/db/table", "db/table"},
{"/a/b/db///////table", "db/table"},
{"/a/b////db///////table", "db/table"},
{"/var/tmp/mysqld.1/#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
{"db/table", "db/table"},
{"ddd/t", "ddd/t"},
{"d/ttt", "d/ttt"},
{"d/t", "d/t"},
{".\\mysqltest\\t1", "mysqltest/t1"},
{".\\test\\#sql-842b_2", "test/#sql-842b_2"},
{".\\test\\#sql-85a3_10", "test/#sql-85a3_10"},
{".\\test\\#sql2-842b-2", "test/#sql2-842b-2"},
{".\\test\\bug29807", "test/bug29807"},
{".\\test\\foo", "test/foo"},
{".\\test\\innodb_bug52663", "test/innodb_bug52663"},
{".\\test\\t", "test/t"},
{".\\test\\t1", "test/t1"},
{".\\test\\t10", "test/t10"},
{"C:\\a\\b\\db\\table", "db/table"},
{"C:\\a\\b\\db\\\\\\\\\\\\\\table", "db/table"},
{"C:\\a\\b\\\\\\\\db\\\\\\\\\\\\\\table", "db/table"},
{"C:\\var\\tmp\\mysqld.1\\#sql842b_2_10", "mysqld.1/#sql842b_2_10"},
{"db\\table", "db/table"},
{"ddd\\t", "ddd/t"},
{"d\\ttt", "d/ttt"},
{"d\\t", "d/t"},
};
for (size_t i = 0; i < UT_ARR_SIZE(test_data); i++) {
printf("test_normalize_table_name_low(): "
"testing \"%s\", expected \"%s\"... ",
test_data[i][0], test_data[i][1]);
normalize_table_name_low(norm_name, test_data[i][0], FALSE);
if (strcmp(norm_name, test_data[i][1]) == 0) {
printf("ok\n");
} else {
printf("got \"%s\"\n", norm_name);
ut_error;
}
}
}
#endif /* !DBUG_OFF */
/********************************************************************//**
Get the upper limit of the MySQL integral and floating-point type.
@return maximum allowed value for the field */
@ -4262,6 +4360,8 @@ ha_innobase::open(
THD* thd;
ulint retries = 0;
char* is_part = NULL;
ibool par_case_name_set = FALSE;
char par_case_name[MAX_FULL_NAME_LEN + 1];
DBUG_ENTER("ha_innobase::open");
@ -4292,51 +4392,107 @@ ha_innobase::open(
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
}
/* Create buffers for packing the fields of a record. Why
table->stored_rec_length did not work here? Obviously, because char
fields when packed actually became 1 byte longer, when we also
stored the string length as the first byte. */
upd_and_key_val_buff_len =
table->s->stored_rec_length + table->s->max_key_length
+ MAX_REF_PARTS * 3;
if (!(uchar*) my_multi_malloc(MYF(MY_WME),
&upd_buff, upd_and_key_val_buff_len,
&key_val_buff, upd_and_key_val_buff_len,
NullS)) {
free_share(share);
DBUG_RETURN(1);
}
/* Will be allocated if it is needed in ::update_row() */
upd_buf = NULL;
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. */
#ifdef __WIN__
is_part = strstr(norm_name, "#p#");
#else
is_part = strstr(norm_name, "#P#");
#endif /* __WIN__ */
retry:
/* Get pointer to a table object in InnoDB dictionary cache */
ib_table = dict_table_get(norm_name, TRUE);
if (srv_pass_corrupt_table <= 1 && ib_table && ib_table->is_corrupt) {
free_share(share);
my_free(upd_buff);
my_free(upd_buf);
upd_buf = NULL;
upd_buf_size = 0;
DBUG_RETURN(HA_ERR_CRASHED_ON_USAGE);
}
share->ib_table = ib_table;
if (NULL == ib_table) {
if (is_part && retries < 10) {
++retries;
os_thread_sleep(100000);
goto retry;
/* 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
for sub-partition names as well. InnoDB always
normalises file names to lower case on Windows, this
can potentially cause problems when copying/moving
tables between platforms.
1) If boot against an installation from Windows
platform, then its partition table name could
be all be in lower case in system tables. So we
will need to check lower case name when load table.
2) If we boot an installation from other case
sensitive platform in Windows, we might need to
check the existence of table name without lowering
case them in the system table. */
if (innobase_get_lower_case_table_names() == 1) {
if (!par_case_name_set) {
#ifndef __WIN__
/* Check for the table using lower
case name, including the partition
separator "P" */
memcpy(par_case_name, norm_name,
strlen(norm_name));
par_case_name[strlen(norm_name)] = 0;
innobase_casedn_str(par_case_name);
#else
/* On Windows platfrom, check
whether there exists table name in
system table whose name is
not being normalized to lower case */
normalize_table_name_low(
par_case_name, name, FALSE);
#endif
par_case_name_set = TRUE;
}
ib_table = dict_table_get(
par_case_name, FALSE);
}
if (!ib_table) {
++retries;
os_thread_sleep(100000);
goto retry;
} else {
#ifndef __WIN__
sql_print_warning("Partition table %s opened "
"after converting to lower "
"case. The table may have "
"been moved from a case "
"in-sensitive file system. "
"Please recreate table in "
"the current file system\n",
norm_name);
#else
sql_print_warning("Partition table %s opened "
"after skipping the step to "
"lower case the table name. "
"The table may have been "
"moved from a case sensitive "
"file system. Please "
"recreate table in the "
"current file system\n",
norm_name);
#endif
goto table_opened;
}
}
if (is_part) {
@ -4361,12 +4517,13 @@ retry:
"how you can resolve the problem.\n",
norm_name);
free_share(share);
my_free(upd_buff);
my_errno = ENOENT;
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
table_opened:
if (ib_table->ibd_file_missing && !thd_tablespace_op(thd)) {
sql_print_error("MySQL is trying to open a table handle but "
"the .ibd file for\ntable %s does not exist.\n"
@ -4377,16 +4534,14 @@ retry:
"how you can resolve the problem.\n",
norm_name);
free_share(share);
my_free(upd_buff);
my_errno = ENOENT;
dict_table_decrement_handle_count(ib_table, FALSE);
DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
}
prebuilt = row_create_prebuilt(ib_table);
prebuilt = row_create_prebuilt(ib_table, table->s->stored_rec_length);
prebuilt->mysql_row_len = table->s->stored_rec_length;;
prebuilt->default_rec = table->s->default_values;
ut_ad(prebuilt->default_rec);
@ -4575,7 +4730,13 @@ ha_innobase::close(void)
row_prebuilt_free(prebuilt, FALSE);
my_free(upd_buff);
if (upd_buf != NULL) {
ut_ad(upd_buf_size != 0);
my_free(upd_buf);
upd_buf = NULL;
upd_buf_size = 0;
}
free_share(share);
/* Tell InnoDB server that there might be work for
@ -6101,6 +6262,23 @@ ha_innobase::update_row(
ut_a(prebuilt->trx == trx);
if (upd_buf == NULL) {
ut_ad(upd_buf_size == 0);
/* Create a buffer for packing the fields of a record. Why
table->stored_rec_length did not work here? Obviously, because char
fields when packed actually became 1 byte longer, when we also
stored the string length as the first byte. */
upd_buf_size = table->s->stored_rec_length + table->s->max_key_length
+ MAX_REF_PARTS * 3;
upd_buf = (uchar*) my_malloc(upd_buf_size, MYF(MY_WME));
if (upd_buf == NULL) {
upd_buf_size = 0;
DBUG_RETURN(HA_ERR_OUT_OF_MEM);
}
}
ha_statistic_increment(&SSV::ha_update_count);
if (share->ib_table->is_corrupt) {
@ -6117,11 +6295,10 @@ ha_innobase::update_row(
}
/* Build an update vector from the modified fields in the rows
(uses upd_buff of the handle) */
(uses upd_buf of the handle) */
calc_row_difference(uvect, (uchar*) old_row, new_row, table,
upd_buff, (ulint)upd_and_key_val_buff_len,
prebuilt, user_thd);
upd_buf, upd_buf_size, prebuilt, user_thd);
/* This is not a delete */
prebuilt->upd_node->is_delete = FALSE;
@ -6492,6 +6669,7 @@ ha_innobase::index_read(
DBUG_ENTER("index_read");
ut_a(prebuilt->trx == thd_to_trx(user_thd));
ut_ad(key_len != 0 || find_flag != HA_READ_KEY_EXACT);
ha_statistic_increment(&SSV::ha_read_key_count);
@ -6524,8 +6702,7 @@ ha_innobase::index_read(
row_sel_convert_mysql_key_to_innobase(
prebuilt->search_tuple,
(byte*) key_val_buff,
(ulint)upd_and_key_val_buff_len,
srch_key_val1, sizeof(srch_key_val1),
index,
(byte*) key_ptr,
(ulint) key_len,
@ -7695,6 +7872,8 @@ ha_innobase::create(
DBUG_RETURN(HA_ERR_TO_BIG_ROW);
}
ut_a(strlen(name) < sizeof(name2));
strcpy(name2, name);
normalize_table_name(norm_name, name2);
@ -8138,6 +8317,11 @@ ha_innobase::delete_table(
DBUG_ENTER("ha_innobase::delete_table");
DBUG_EXECUTE_IF(
"test_normalize_table_name_low",
test_normalize_table_name_low();
);
/* Strangely, MySQL passes the table name without the '.frm'
extension, in contrast to ::create */
normalize_table_name(norm_name, name);
@ -8299,6 +8483,8 @@ innobase_rename_table(
normalize_table_name(norm_to, to);
normalize_table_name(norm_from, from);
DEBUG_SYNC_C("innodb_rename_table_ready");
/* Serialize data dictionary operations with dictionary mutex:
no deadlocks can occur then in these operations */
@ -8417,12 +8603,6 @@ ha_innobase::records_in_range(
{
KEY* key;
dict_index_t* index;
uchar* key_val_buff2 = (uchar*) my_malloc(
table->s->stored_rec_length
+ table->s->max_key_length + 100,
MYF(MY_FAE));
ulint buff2_len = table->s->stored_rec_length
+ table->s->max_key_length + 100;
dtuple_t* range_start;
dtuple_t* range_end;
ib_int64_t n_rows;
@ -8479,8 +8659,8 @@ ha_innobase::records_in_range(
dict_index_copy_types(range_end, index, key_parts);
row_sel_convert_mysql_key_to_innobase(
range_start, (byte*) key_val_buff,
(ulint)upd_and_key_val_buff_len,
range_start,
srch_key_val1, sizeof(srch_key_val1),
index,
(byte*) (min_key ? min_key->key :
(const uchar*) 0),
@ -8491,8 +8671,9 @@ ha_innobase::records_in_range(
: range_start->n_fields == 0);
row_sel_convert_mysql_key_to_innobase(
range_end, (byte*) key_val_buff2,
buff2_len, index,
range_end,
srch_key_val2, sizeof(srch_key_val2),
index,
(byte*) (max_key ? max_key->key :
(const uchar*) 0),
(ulint) (max_key ? max_key->length : 0),
@ -8519,7 +8700,6 @@ ha_innobase::records_in_range(
mem_heap_free(heap);
func_exit:
my_free(key_val_buff2);
prebuilt->trx->op_info = (char*)"";
@ -12382,6 +12562,13 @@ static MYSQL_SYSVAR_BOOL(use_sys_stats_table, innobase_use_sys_stats_table,
"So you should use ANALYZE TABLE command intentionally.",
NULL, NULL, FALSE);
#ifdef UNIV_DEBUG
static MYSQL_SYSVAR_ULONG(sys_stats_root_page, innobase_sys_stats_root_page,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Override the SYS_STATS root page id, 0 = no override (for testing only)",
NULL, NULL, 0, 0, ULONG_MAX, 0);
#endif
static MYSQL_SYSVAR_BOOL(adaptive_hash_index, btr_search_enabled,
PLUGIN_VAR_OPCMDARG,
"Enable InnoDB adaptive hash index (enabled by default). "
@ -12598,6 +12785,13 @@ static MYSQL_SYSVAR_ULONG(read_ahead_threshold, srv_read_ahead_threshold,
"trigger a readahead.",
NULL, NULL, 56, 0, 64, 0);
#ifdef UNIV_DEBUG
static MYSQL_SYSVAR_UINT(trx_rseg_n_slots_debug, trx_rseg_n_slots_debug,
PLUGIN_VAR_RQCMDARG,
"Debug flags for InnoDB to limit TRX_RSEG_N_SLOTS for trx_rsegf_undo_find_free()",
NULL, NULL, 0, 0, 1024, 0);
#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_LONGLONG(ibuf_max_size, srv_ibuf_max_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"The maximum size of the insert buffer. (in bytes)",
@ -12719,14 +12913,6 @@ static MYSQL_SYSVAR_ENUM(adaptive_flushing_method, srv_adaptive_flushing_method,
"Choose method of innodb_adaptive_flushing. (native, [estimate], keep_average)",
NULL, innodb_adaptive_flushing_method_update, 1, &adaptive_flushing_method_typelib);
#ifdef UNIV_DEBUG
static MYSQL_SYSVAR_ULONG(flush_checkpoint_debug, srv_flush_checkpoint_debug,
PLUGIN_VAR_RQCMDARG,
"Debug flags for InnoDB flushing and checkpointing (0=none,"
"1=stop preflush and checkpointing)",
NULL, NULL, 0, 0, 1, 0);
#endif
static MYSQL_SYSVAR_ULONG(import_table_from_xtrabackup, srv_expand_import,
PLUGIN_VAR_RQCMDARG,
"Enable/Disable converting automatically *.ibd files when import tablespace.",
@ -12832,6 +13018,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(stats_auto_update),
MYSQL_SYSVAR(stats_update_need_lock),
MYSQL_SYSVAR(use_sys_stats_table),
#ifdef UNIV_DEBUG_never /* disable this flag. --innodb-sys-stats becomes ambiguous */
MYSQL_SYSVAR(sys_stats_root_page),
#endif
MYSQL_SYSVAR(stats_sample_pages),
MYSQL_SYSVAR(adaptive_hash_index),
MYSQL_SYSVAR(adaptive_hash_index_partitions),
@ -12873,9 +13062,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(purge_threads),
MYSQL_SYSVAR(purge_batch_size),
MYSQL_SYSVAR(rollback_segments),
#ifdef UNIV_DEBUG
MYSQL_SYSVAR(flush_checkpoint_debug),
#endif
#ifdef UNIV_DEBUG_never /* disable this flag. --innodb-trx becomes ambiguous */
MYSQL_SYSVAR(trx_rseg_n_slots_debug),
#endif /* UNIV_DEBUG */
MYSQL_SYSVAR(corrupt_table_action),
MYSQL_SYSVAR(lazy_drop_table),
MYSQL_SYSVAR(fake_changes),

View file

@ -79,13 +79,14 @@ class ha_innobase: public handler
INNOBASE_SHARE* share; /*!< information for MySQL
table locking */
uchar* upd_buff; /*!< buffer used in updates */
uchar* key_val_buff; /*!< buffer used in converting
uchar* upd_buf; /*!< buffer used in updates */
ulint upd_buf_size; /*!< the size of upd_buf in bytes */
uchar srch_key_val1[REC_VERSION_56_MAX_INDEX_COL_LEN + 2];
uchar srch_key_val2[REC_VERSION_56_MAX_INDEX_COL_LEN + 2];
/*!< buffers used in converting
search key values from MySQL format
to Innodb format */
ulong upd_and_key_val_buff_len;
/* the length of each of the previous
two buffers */
to InnoDB format. "+ 2" for the two
bytes where the length is stored */
Table_flags int_table_flags;
uint primary_key;
ulong start_of_scan; /*!< this is set to 1 when we are

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 2005, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 2005, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -878,6 +878,8 @@ ha_innobase::add_index(
prebuilt->table, indexed_table,
index, num_of_idx, table);
DBUG_EXECUTE_IF("crash_innodb_add_index_after", DBUG_SUICIDE(););
error_handling:
/* After an error, remove all those index definitions from the
dictionary which were defined. */
@ -1020,7 +1022,12 @@ ha_innobase::final_add_index(
row_prebuilt_free(prebuilt, TRUE);
error = row_merge_drop_table(trx, old_table);
add->indexed_table->n_mysql_handles_opened++;
prebuilt = row_create_prebuilt(add->indexed_table);
prebuilt = row_create_prebuilt(add->indexed_table,
0 /* XXX Do we know the mysql_row_len here?
Before the addition of this parameter to
row_create_prebuilt() the mysql_row_len
member was left 0 (from zalloc) in the
prebuilt object. */);
}
err = convert_error_code_to_mysql(
@ -1154,7 +1161,9 @@ ha_innobase::prepare_drop_index(
goto func_exit;
}
rw_lock_x_lock(dict_index_get_lock(index));
index->to_be_dropped = TRUE;
rw_lock_x_unlock(dict_index_get_lock(index));
}
/* If FOREIGN_KEY_CHECKS = 1 you may not drop an index defined
@ -1273,7 +1282,9 @@ func_exit:
= dict_table_get_first_index(prebuilt->table);
do {
rw_lock_x_lock(dict_index_get_lock(index));
index->to_be_dropped = FALSE;
rw_lock_x_unlock(dict_index_get_lock(index));
index = dict_table_get_next_index(index);
} while (index);
}
@ -1339,7 +1350,9 @@ ha_innobase::final_drop_index(
for (index = dict_table_get_first_index(prebuilt->table);
index; index = dict_table_get_next_index(index)) {
rw_lock_x_lock(dict_index_get_lock(index));
index->to_be_dropped = FALSE;
rw_lock_x_unlock(dict_index_get_lock(index));
}
goto func_exit;

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1997, 2011, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 1997, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -1523,7 +1523,7 @@ ibuf_add_ops(
for (i = 0; i < IBUF_OP_COUNT; i++) {
#ifdef HAVE_ATOMIC_BUILTINS
os_atomic_increment_ulint(&arr[i], ops[i]);
(void) os_atomic_increment_ulint(&arr[i], ops[i]);
#else /* HAVE_ATOMIC_BUILTINS */
arr[i] += ops[i];
#endif /* HAVE_ATOMIC_BUILTINS */
@ -2222,14 +2222,14 @@ ibool
ibuf_add_free_page(void)
/*====================*/
{
mtr_t mtr;
page_t* header_page;
ulint flags;
ulint zip_size;
ulint page_no;
page_t* page;
page_t* root;
page_t* bitmap_page;
mtr_t mtr;
page_t* header_page;
ulint flags;
ulint zip_size;
buf_block_t* block;
page_t* page;
page_t* root;
page_t* bitmap_page;
mtr_start(&mtr);
@ -2250,29 +2250,24 @@ ibuf_add_free_page(void)
of a deadlock. This is the reason why we created a special ibuf
header page apart from the ibuf tree. */
page_no = fseg_alloc_free_page(
block = fseg_alloc_free_page(
header_page + IBUF_HEADER + IBUF_TREE_SEG_HEADER, 0, FSP_UP,
&mtr);
if (UNIV_UNLIKELY(page_no == FIL_NULL)) {
if (block == NULL) {
mtr_commit(&mtr);
return(FALSE);
} else {
buf_block_t* block = buf_page_get(
IBUF_SPACE_ID, 0, page_no, RW_X_LATCH, &mtr);
ibuf_enter(&mtr);
mutex_enter(&ibuf_mutex);
root = ibuf_tree_root_get(&mtr);
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
page = buf_block_get_frame(block);
}
ut_ad(rw_lock_get_x_lock_count(&block->lock) == 1);
ibuf_enter(&mtr);
mutex_enter(&ibuf_mutex);
root = ibuf_tree_root_get(&mtr);
buf_block_dbg_add_level(block, SYNC_IBUF_TREE_NODE_NEW);
page = buf_block_get_frame(block);
/* Add the page to the free list and update the ibuf size data */
flst_add_last(root + PAGE_HEADER + PAGE_BTR_IBUF_FREE_LIST,
@ -2288,12 +2283,13 @@ ibuf_add_free_page(void)
(level 2 page) */
bitmap_page = ibuf_bitmap_get_map_page(
IBUF_SPACE_ID, page_no, zip_size, &mtr);
IBUF_SPACE_ID, buf_block_get_page_no(block), zip_size, &mtr);
mutex_exit(&ibuf_mutex);
ibuf_bitmap_page_set_bits(
bitmap_page, page_no, zip_size, IBUF_BITMAP_IBUF, TRUE, &mtr);
bitmap_page, buf_block_get_page_no(block), zip_size,
IBUF_BITMAP_IBUF, TRUE, &mtr);
ibuf_mtr_commit(&mtr);
@ -2588,7 +2584,15 @@ ibuf_get_merge_page_nos_func(
} else {
rec_page_no = ibuf_rec_get_page_no(mtr, rec);
rec_space_id = ibuf_rec_get_space(mtr, rec);
ut_ad(rec_page_no > IBUF_TREE_ROOT_PAGE_NO);
/* In the system tablespace, the smallest
possible secondary index leaf page number is
bigger than IBUF_TREE_ROOT_PAGE_NO (4). In
other tablespaces, the clustered index tree is
created at page 3, which makes page 4 the
smallest possible secondary index leaf page
(and that only after DROP INDEX). */
ut_ad(rec_page_no
> IBUF_TREE_ROOT_PAGE_NO - (rec_space_id != 0));
}
#ifdef UNIV_IBUF_DEBUG
@ -3920,6 +3924,7 @@ ibuf_insert_to_index_page_low(
fputs("InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr);
ut_ad(0);
}
/************************************************************************
@ -3970,9 +3975,10 @@ ibuf_insert_to_index_page(
"InnoDB: but the number of fields does not match!\n",
stderr);
dump:
buf_page_print(page, 0);
buf_page_print(page, 0, BUF_PAGE_PRINT_NO_CRASH);
dtuple_print(stderr, entry);
ut_ad(0);
fputs("InnoDB: The table where where"
" this index record belongs\n"
@ -4113,6 +4119,11 @@ ibuf_set_del_mark(
TRUE, mtr);
}
} else {
const page_t* page
= page_cur_get_page(&page_cur);
const buf_block_t* block
= page_cur_get_block(&page_cur);
ut_print_timestamp(stderr);
fputs(" InnoDB: unable to find a record to delete-mark\n",
stderr);
@ -4121,10 +4132,14 @@ ibuf_set_del_mark(
fputs("\n"
"InnoDB: record ", stderr);
rec_print(stderr, page_cur_get_rec(&page_cur), index);
putc('\n', stderr);
fputs("\n"
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n", stderr);
fprintf(stderr, "\nspace %u offset %u"
" (%u records, index id %llu)\n"
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n",
(unsigned) buf_block_get_space(block),
(unsigned) buf_block_get_page_no(block),
(unsigned) page_get_n_recs(page),
(ulonglong) btr_page_get_index_id(page));
ut_ad(0);
}
}
@ -4168,12 +4183,31 @@ ibuf_delete(
offsets = rec_get_offsets(
rec, index, offsets, ULINT_UNDEFINED, &heap);
/* Refuse to delete the last record. */
ut_a(page_get_n_recs(page) > 1);
if (page_get_n_recs(page) <= 1
|| !(REC_INFO_DELETED_FLAG
& rec_get_info_bits(rec, page_is_comp(page)))) {
/* Refuse to purge the last record or a
record that has not been marked for deletion. */
ut_print_timestamp(stderr);
fputs(" InnoDB: unable to purge a record\n",
stderr);
fputs("InnoDB: tuple ", stderr);
dtuple_print(stderr, entry);
fputs("\n"
"InnoDB: record ", stderr);
rec_print_new(stderr, rec, offsets);
fprintf(stderr, "\nspace %u offset %u"
" (%u records, index id %llu)\n"
"InnoDB: Submit a detailed bug report"
" to http://bugs.mysql.com\n",
(unsigned) buf_block_get_space(block),
(unsigned) buf_block_get_page_no(block),
(unsigned) page_get_n_recs(page),
(ulonglong) btr_page_get_index_id(page));
/* The record should have been marked for deletion. */
ut_ad(REC_INFO_DELETED_FLAG
& rec_get_info_bits(rec, page_is_comp(page)));
ut_ad(0);
return;
}
lock_update_delete(block, rec);
@ -4259,6 +4293,7 @@ ibuf_restore_pos(
fprintf(stderr, "InnoDB: ibuf tree ok\n");
fflush(stderr);
ut_ad(0);
}
return(FALSE);
@ -4441,7 +4476,7 @@ ibuf_merge_or_delete_for_page(
function. When the counter is > 0, that prevents tablespace
from being dropped. */
tablespace_being_deleted = fil_inc_pending_ibuf_merges(space);
tablespace_being_deleted = fil_inc_pending_ops(space);
if (UNIV_UNLIKELY(tablespace_being_deleted)) {
/* Do not try to read the bitmap page from space;
@ -4467,7 +4502,7 @@ ibuf_merge_or_delete_for_page(
/* No inserts buffered for this page */
if (!tablespace_being_deleted) {
fil_decr_pending_ibuf_merges(space);
fil_decr_pending_ops(space);
}
return;
@ -4516,12 +4551,14 @@ ibuf_merge_or_delete_for_page(
bitmap_page = ibuf_bitmap_get_map_page(space, page_no,
zip_size, &mtr);
buf_page_print(bitmap_page, 0);
buf_page_print(bitmap_page, 0,
BUF_PAGE_PRINT_NO_CRASH);
ibuf_mtr_commit(&mtr);
fputs("\nInnoDB: Dump of the page:\n", stderr);
buf_page_print(block->frame, 0);
buf_page_print(block->frame, 0,
BUF_PAGE_PRINT_NO_CRASH);
fprintf(stderr,
"InnoDB: Error: corruption in the tablespace."
@ -4541,6 +4578,7 @@ ibuf_merge_or_delete_for_page(
(ulong) page_no,
(ulong)
fil_page_get_type(block->frame));
ut_ad(0);
}
}
@ -4747,7 +4785,7 @@ reset_bit:
mem_heap_free(heap);
#ifdef HAVE_ATOMIC_BUILTINS
os_atomic_increment_ulint(&ibuf->n_merges, 1);
(void) os_atomic_increment_ulint(&ibuf->n_merges, 1);
ibuf_add_ops(ibuf->n_merged_ops, mops);
ibuf_add_ops(ibuf->n_discarded_ops, dops);
#else /* HAVE_ATOMIC_BUILTINS */
@ -4763,7 +4801,7 @@ reset_bit:
if (update_ibuf_bitmap && !tablespace_being_deleted) {
fil_decr_pending_ibuf_merges(space);
fil_decr_pending_ops(space);
}
#ifdef UNIV_IBUF_COUNT_DEBUG

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1994, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -92,6 +92,26 @@ insert/delete buffer when the record is not in the buffer pool. */
buffer when the record is not in the buffer pool. */
#define BTR_DELETE 8192
/**************************************************************//**
Report that an index page is corrupted. */
UNIV_INTERN
void
btr_corruption_report(
/*==================*/
const buf_block_t* block, /*!< in: corrupted block */
const dict_index_t* index) /*!< in: index tree */
UNIV_COLD __attribute__((nonnull));
/** Assert that a B-tree page is not corrupted.
@param block buffer block containing a B-tree page
@param index the B-tree index */
#define btr_assert_not_corrupted(block, index) \
if ((ibool) !!page_is_comp(buf_block_get_frame(block)) \
!= dict_table_is_comp((index)->table)) { \
btr_corruption_report(block, index); \
ut_error; \
}
#ifdef UNIV_BLOB_DEBUG
# include "ut0rbt.h"
/** An index->blobs entry for keeping track of off-page column references */
@ -569,11 +589,14 @@ UNIV_INTERN
ibool
btr_compress(
/*=========*/
btr_cur_t* cursor, /*!< in: cursor on the page to merge or lift;
the page must not be empty: in record delete
use btr_discard_page if the page would become
empty */
mtr_t* mtr); /*!< in: mtr */
btr_cur_t* cursor, /*!< in/out: cursor on the page to merge
or lift; the page must not be empty:
when deleting records, use btr_discard_page()
if the page would become empty */
ibool adjust, /*!< in: TRUE if should adjust the
cursor position even if compression occurs */
mtr_t* mtr) /*!< in/out: mini-transaction */
__attribute__((nonnull));
/*************************************************************//**
Discards a page from a B-tree. This is used to remove the last record from
a B-tree page: the whole page must be removed at the same time. This cannot
@ -614,17 +637,23 @@ btr_parse_page_reorganize(
#ifndef UNIV_HOTBACKUP
/**************************************************************//**
Gets the number of pages in a B-tree.
@return number of pages */
@return number of pages, or ULINT_UNDEFINED if the index is unavailable */
UNIV_INTERN
ulint
btr_get_size(
/*=========*/
dict_index_t* index, /*!< in: index */
ulint flag); /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
mtr_t* mtr) /*!< in/out: mini-transaction where index
is s-latched */
__attribute__((nonnull, warn_unused_result));
/**************************************************************//**
Allocates a new file page to be used in an index tree. NOTE: we assume
that the caller has made the reservation for free extents!
@return new allocated block, x-latched; NULL if out of space */
@retval NULL if no page could be allocated
@retval block, rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
UNIV_INTERN
buf_block_t*
btr_page_alloc(
@ -635,7 +664,12 @@ btr_page_alloc(
page split is made */
ulint level, /*!< in: level where the page is placed
in the tree */
mtr_t* mtr); /*!< in: mtr */
mtr_t* mtr, /*!< in/out: mini-transaction
for the allocation */
mtr_t* init_mtr) /*!< in/out: mini-transaction
for x-latching and initializing
the page */
__attribute__((nonnull, warn_unused_result));
/**************************************************************//**
Frees a file page used in an index tree. NOTE: cannot free field external
storage pages because the page must contain info on its level. */

View file

@ -279,7 +279,7 @@ btr_node_ptr_get_child_page_no(
"InnoDB: a nonsensical page number 0"
" in a node ptr record at offset %lu\n",
(ulong) page_offset(rec));
buf_page_print(page_align(rec), 0);
buf_page_print(page_align(rec), 0, 0);
}
return(page_no);

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1994, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1994, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -36,6 +36,9 @@ Created 10/16/1994 Heikki Tuuri
#define BTR_NO_LOCKING_FLAG 2 /* do no record lock checking */
#define BTR_KEEP_SYS_FLAG 4 /* sys fields will be found from the
update vector or inserted entry */
#define BTR_KEEP_POS_FLAG 8 /* btr_cur_pessimistic_update()
must keep cursor position when
moving columns to big_rec */
#ifndef UNIV_HOTBACKUP
#include "que0types.h"
@ -310,7 +313,9 @@ btr_cur_pessimistic_update(
/*=======================*/
ulint flags, /*!< in: undo logging, locking, and rollback
flags */
btr_cur_t* cursor, /*!< in: cursor on the record to update */
btr_cur_t* cursor, /*!< in/out: cursor on the record to update;
cursor may become invalid if *big_rec == NULL
|| !(flags & BTR_KEEP_POS_FLAG) */
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
big_rec_t** big_rec,/*!< out: big rec vector whose fields have to
be stored externally by the caller, or NULL */
@ -364,10 +369,13 @@ UNIV_INTERN
ibool
btr_cur_compress_if_useful(
/*=======================*/
btr_cur_t* cursor, /*!< in: cursor on the page to compress;
btr_cur_t* cursor, /*!< in/out: cursor on the page to compress;
cursor does not stay valid if compression
occurs */
mtr_t* mtr); /*!< in: mtr */
ibool adjust, /*!< in: TRUE if should adjust the
cursor position even if compression occurs */
mtr_t* mtr) /*!< in/out: mini-transaction */
__attribute__((nonnull));
/*******************************************************//**
Removes the record on which the tree cursor is positioned. It is assumed
that the mtr has an x-latch on the page where the cursor is positioned,
@ -492,6 +500,27 @@ btr_cur_disown_inherited_fields(
const upd_t* update, /*!< in: update vector */
mtr_t* mtr) /*!< in/out: mini-transaction */
__attribute__((nonnull(2,3,4,5,6)));
/** Operation code for btr_store_big_rec_extern_fields(). */
enum blob_op {
/** Store off-page columns for a freshly inserted record */
BTR_STORE_INSERT = 0,
/** Store off-page columns for an insert by update */
BTR_STORE_INSERT_UPDATE,
/** Store off-page columns for an update */
BTR_STORE_UPDATE
};
/*******************************************************************//**
Determine if an operation on off-page columns is an update.
@return TRUE if op != BTR_STORE_INSERT */
UNIV_INLINE
ibool
btr_blob_op_is_update(
/*==================*/
enum blob_op op) /*!< in: operation */
__attribute__((warn_unused_result));
/*******************************************************************//**
Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand.
@ -499,52 +528,23 @@ The fields are stored on pages allocated from leaf node
file segment of the index tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
UNIV_INTERN
ulint
btr_store_big_rec_extern_fields_func(
/*=================================*/
enum db_err
btr_store_big_rec_extern_fields(
/*============================*/
dict_index_t* index, /*!< in: index of rec; the index tree
MUST be X-latched */
buf_block_t* rec_block, /*!< in/out: block containing rec */
rec_t* rec, /*!< in: record */
rec_t* rec, /*!< in/out: record */
const ulint* offsets, /*!< in: rec_get_offsets(rec, index);
the "external storage" flags in offsets
will not correspond to rec when
this function returns */
#ifdef UNIV_DEBUG
mtr_t* local_mtr, /*!< in: mtr containing the
latch to rec and to the tree */
#endif /* UNIV_DEBUG */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
ibool update_in_place,/*! in: TRUE if the record is updated
in place (not delete+insert) */
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
const big_rec_t*big_rec_vec) /*!< in: vector containing fields
const big_rec_t*big_rec_vec, /*!< in: vector containing fields
to be stored externally */
__attribute__((nonnull));
/** Stores the fields in big_rec_vec to the tablespace and puts pointers to
them in rec. The extern flags in rec will have to be set beforehand.
The fields are stored on pages allocated from leaf node
file segment of the index tree.
@param index in: clustered index; MUST be X-latched by mtr
@param b in/out: block containing rec; MUST be X-latched by mtr
@param rec in/out: clustered index record
@param offsets in: rec_get_offsets(rec, index);
the "external storage" flags in offsets will not be adjusted
@param mtr in: mini-transaction that holds x-latch on index and b
@param upd in: TRUE if the record is updated in place (not delete+insert)
@param big in: vector containing fields to be stored externally
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
#ifdef UNIV_DEBUG
# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
btr_store_big_rec_extern_fields_func(index,b,rec,offsets,mtr,upd,big)
#elif defined UNIV_BLOB_LIGHT_DEBUG
# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
btr_store_big_rec_extern_fields_func(index,b,rec,offsets,upd,big)
#else
# define btr_store_big_rec_extern_fields(index,b,rec,offsets,mtr,upd,big) \
btr_store_big_rec_extern_fields_func(index,b,rec,offsets,big)
#endif
mtr_t* btr_mtr, /*!< in: mtr containing the
latches to the clustered index */
enum blob_op op) /*! in: operation code */
__attribute__((nonnull, warn_unused_result));
/*******************************************************************//**
Frees the space in an externally stored field to the file space

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
Copyright (c) 1994, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -139,7 +139,7 @@ btr_cur_compress_recommendation(
btr_cur_t* cursor, /*!< in: btr cursor */
mtr_t* mtr) /*!< in: mtr */
{
page_t* page;
const page_t* page;
ut_ad(mtr_memo_contains(mtr, btr_cur_get_block(cursor),
MTR_MEMO_PAGE_X_FIX));
@ -197,4 +197,25 @@ btr_cur_can_delete_without_compress(
return(TRUE);
}
/*******************************************************************//**
Determine if an operation on off-page columns is an update.
@return TRUE if op != BTR_STORE_INSERT */
UNIV_INLINE
ibool
btr_blob_op_is_update(
/*==================*/
enum blob_op op) /*!< in: operation */
{
switch (op) {
case BTR_STORE_INSERT:
return(FALSE);
case BTR_STORE_INSERT_UPDATE:
case BTR_STORE_UPDATE:
return(TRUE);
}
ut_ad(0);
return(FALSE);
}
#endif /* !UNIV_HOTBACKUP */

View file

@ -53,6 +53,16 @@ UNIV_INTERN
btr_pcur_t*
btr_pcur_create_for_mysql(void);
/*============================*/
/**************************************************************//**
Resets a persistent cursor object, freeing ::old_rec_buf if it is
allocated and resetting the other members to their initial values. */
UNIV_INTERN
void
btr_pcur_reset(
/*===========*/
btr_pcur_t* cursor);/*!< in, out: persistent cursor */
/**************************************************************//**
Frees the memory for a persistent cursor object. */
UNIV_INTERN

View file

@ -1,6 +1,6 @@
/*****************************************************************************
Copyright (c) 1995, 2010, Innobase Oy. All Rights Reserved.
Copyright (c) 1995, 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
@ -11,8 +11,8 @@ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License along with
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
Place, Suite 330, Boston, MA 02111-1307 USA
this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
*****************************************************************************/
@ -611,6 +611,31 @@ buf_block_get_modify_clock(
#else /* !UNIV_HOTBACKUP */
# define buf_block_modify_clock_inc(block) ((void) 0)
#endif /* !UNIV_HOTBACKUP */
/*******************************************************************//**
Increments the bufferfix count. */
UNIV_INLINE
void
buf_block_buf_fix_inc_func(
/*=======================*/
#ifdef UNIV_SYNC_DEBUG
const char* file, /*!< in: file name */
ulint line, /*!< in: line */
#endif /* UNIV_SYNC_DEBUG */
buf_block_t* block) /*!< in/out: block to bufferfix */
__attribute__((nonnull));
#ifdef UNIV_SYNC_DEBUG
/** Increments the bufferfix count.
@param b in/out: block to bufferfix
@param f in: file name where requested
@param l in: line number where requested */
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(f,l,b)
#else /* UNIV_SYNC_DEBUG */
/** Increments the bufferfix count.
@param b in/out: block to bufferfix
@param f in: file name where requested
@param l in: line number where requested */
# define buf_block_buf_fix_inc(b,f,l) buf_block_buf_fix_inc_func(b)
#endif /* UNIV_SYNC_DEBUG */
/********************************************************************//**
Calculates a page checksum which is stored to the page when it is written
to a file. Note that we must be careful to calculate the same value
@ -700,6 +725,13 @@ buf_print(void);
/*============*/
#endif /* UNIV_DEBUG_PRINT || UNIV_DEBUG || UNIV_BUF_DEBUG */
#endif /* !UNIV_HOTBACKUP */
enum buf_page_print_flags {
/** Do not crash at the end of buf_page_print(). */
BUF_PAGE_PRINT_NO_CRASH = 1,
/** Do not print the full page dump. */
BUF_PAGE_PRINT_NO_FULL = 2
};
/********************************************************************//**
Prints a page to stderr. */
UNIV_INTERN
@ -707,8 +739,12 @@ void
buf_page_print(
/*===========*/
const byte* read_buf, /*!< in: a database page */
ulint zip_size); /*!< in: compressed page size, or
ulint zip_size, /*!< in: compressed page size, or
0 for uncompressed pages */
ulint flags) /*!< in: 0 or
BUF_PAGE_PRINT_NO_CRASH or
BUF_PAGE_PRINT_NO_FULL */
__attribute__((nonnull));
/********************************************************************//**
Decompress a block.
@return TRUE if successful */
@ -773,11 +809,11 @@ buf_all_freed(void);
/*********************************************************************//**
Checks that there currently are no pending i/o-operations for the buffer
pool.
@return TRUE if there is no pending i/o */
@return number of pending i/o operations */
UNIV_INTERN
ibool
buf_pool_check_no_pending_io(void);
/*==============================*/
ulint
buf_pool_check_num_pending_io(void);
/*===============================*/
/*********************************************************************//**
Invalidates the file pages in the buffer pool when an archive recovery is
completed. All the file pages buffered must be in a replaceable state when

Some files were not shown because too many files have changed in this diff Show more