mirror of
https://github.com/MariaDB/server.git
synced 2026-05-16 20:07:13 +02:00
Merge XtraDB 6 with latest MariaDB 5.1
This commit is contained in:
commit
916f5e1ed8
377 changed files with 207029 additions and 187 deletions
15
.bzrignore
15
.bzrignore
|
|
@ -1444,6 +1444,21 @@ storage/innobase/ib_config.h
|
|||
storage/innobase/ib_config.h.in
|
||||
storage/innobase/mkinstalldirs
|
||||
storage/innobase/stamp-h1
|
||||
storage/xtradb/autom4te-2.53.cache/*
|
||||
storage/xtradb/autom4te-2.53.cache/output.0
|
||||
storage/xtradb/autom4te-2.53.cache/requests
|
||||
storage/xtradb/autom4te-2.53.cache/traces.0
|
||||
storage/xtradb/autom4te.cache/*
|
||||
storage/xtradb/autom4te.cache/output.0
|
||||
storage/xtradb/autom4te.cache/requests
|
||||
storage/xtradb/autom4te.cache/traces.0
|
||||
storage/xtradb/configure.lineno
|
||||
storage/xtradb/conftest.s1
|
||||
storage/xtradb/conftest.subs
|
||||
storage/xtradb/ib_config.h
|
||||
storage/xtradb/ib_config.h.in
|
||||
storage/xtradb/mkinstalldirs
|
||||
storage/xtradb/stamp-h1
|
||||
storage/maria/*.MAD
|
||||
storage/maria/*.MAI
|
||||
storage/maria/ma_rt_test
|
||||
|
|
|
|||
24
BUILD/compile-innodb
Executable file
24
BUILD/compile-innodb
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
# Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh"
|
||||
|
||||
extra_flags="$pentium_cflags $fast_cflags -g"
|
||||
extra_configs="$pentium_configs $static_link --with-plugins=innobase"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
24
BUILD/compile-innodb-debug
Executable file
24
BUILD/compile-innodb-debug
Executable file
|
|
@ -0,0 +1,24 @@
|
|||
#! /bin/sh
|
||||
#
|
||||
# Copyright (c) 2005, 2009, Innobase Oy. All Rights Reserved.
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify it under
|
||||
# the terms of the GNU General Public License as published by the Free Software
|
||||
# Foundation; version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
# FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License along with
|
||||
# this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
# Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
|
||||
path=`dirname $0`
|
||||
. "$path/SETUP.sh" $@ --with-debug=full
|
||||
|
||||
extra_flags="$pentium_cflags $debug_cflags"
|
||||
extra_configs="$pentium_configs $debug_configs --with-plugins=innobase"
|
||||
|
||||
. "$path/FINISH.sh"
|
||||
|
|
@ -263,7 +263,7 @@ IF(WITH_FEDERATED_STORAGE_ENGINE)
|
|||
ADD_SUBDIRECTORY(storage/federated)
|
||||
ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
|
||||
IF(WITH_INNOBASE_STORAGE_ENGINE)
|
||||
ADD_SUBDIRECTORY(storage/innobase)
|
||||
ADD_SUBDIRECTORY(storage/xtradb)
|
||||
ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
|
||||
IF(WITH_MARIA_STORAGE_ENGINE)
|
||||
ADD_SUBDIRECTORY(storage/maria)
|
||||
|
|
|
|||
49
configure.in
49
configure.in
|
|
@ -1729,6 +1729,30 @@ then
|
|||
fi
|
||||
fi
|
||||
|
||||
AC_CACHE_CHECK([whether the compiler provides atomic builtins],
|
||||
[mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([
|
||||
int main()
|
||||
{
|
||||
int foo= -10; int bar= 10;
|
||||
if (!__sync_fetch_and_add(&foo, bar) || foo)
|
||||
return -1;
|
||||
bar= __sync_lock_test_and_set(&foo, bar);
|
||||
if (bar || foo != 10)
|
||||
return -1;
|
||||
bar= __sync_val_compare_and_swap(&bar, foo, 15);
|
||||
if (bar)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
], [mysql_cv_gcc_atomic_builtins=yes],
|
||||
[mysql_cv_gcc_atomic_builtins=no],
|
||||
[mysql_cv_gcc_atomic_builtins=no])])
|
||||
|
||||
if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
|
||||
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
|
||||
[Define to 1 if compiler provides atomic builtins.])
|
||||
fi
|
||||
|
||||
AC_ARG_WITH([atomic-ops],
|
||||
AC_HELP_STRING([--with-atomic-ops=rwlocks|smp|up],
|
||||
[Implement atomic operations using pthread rwlocks or atomic CPU
|
||||
|
|
@ -1742,28 +1766,9 @@ case "$with_atomic_ops" in
|
|||
[Use pthread rwlocks for atomic ops]) ;;
|
||||
"smp") ;;
|
||||
"")
|
||||
AC_CACHE_CHECK([whether the compiler provides atomic builtins],
|
||||
[mysql_cv_gcc_atomic_builtins], [AC_TRY_RUN([
|
||||
int main()
|
||||
{
|
||||
int foo= -10; int bar= 10;
|
||||
if (!__sync_fetch_and_add(&foo, bar) || foo)
|
||||
return -1;
|
||||
bar= __sync_lock_test_and_set(&foo, bar);
|
||||
if (bar || foo != 10)
|
||||
return -1;
|
||||
bar= __sync_val_compare_and_swap(&bar, foo, 15);
|
||||
if (bar)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
], [mysql_cv_gcc_atomic_builtins=yes_but_disabled],
|
||||
[mysql_cv_gcc_atomic_builtins=no],
|
||||
[mysql_cv_gcc_atomic_builtins=no])])
|
||||
|
||||
if test "x$mysql_cv_gcc_atomic_builtins" = xyes; then
|
||||
AC_DEFINE(HAVE_GCC_ATOMIC_BUILTINS, 1,
|
||||
[Define to 1 if compiler provides atomic builtins.])
|
||||
if test "x$mysql_cv_gcc_atomic_builtins" = xyes_but_disabled; then
|
||||
AC_DEFINE([MY_ATOMIC_MODE_GCC_BUILTINS], [1],
|
||||
[Use GCC atomic builtins for atomic ops])
|
||||
fi
|
||||
;;
|
||||
*) AC_MSG_ERROR(["$with_atomic_ops" is not a valid value for --with-atomic-ops]) ;;
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#if defined(__i386__) || defined(_MSC_VER) || \
|
||||
defined(__x86_64__) || defined(HAVE_GCC_ATOMIC_BUILTINS)
|
||||
defined(__x86_64__) || defined(MY_ATOMIC_MODE_GCC_BUILTINS)
|
||||
|
||||
# ifdef MY_ATOMIC_MODE_DUMMY
|
||||
# define LOCK_prefix ""
|
||||
|
|
@ -22,7 +22,7 @@
|
|||
# define LOCK_prefix "lock"
|
||||
# endif
|
||||
|
||||
# ifdef HAVE_GCC_ATOMIC_BUILTINS
|
||||
# ifdef MY_ATOMIC_MODE_GCC_BUILTINS
|
||||
# include "gcc_builtins.h"
|
||||
# elif __GNUC__
|
||||
# include "x86-gcc.h"
|
||||
|
|
|
|||
|
|
@ -98,7 +98,8 @@ extern const double log_10[309];
|
|||
#ifdef BAD_STRING_COMPILER
|
||||
#define strmov(A,B) (memccpy(A,B,0,INT_MAX)-1)
|
||||
#else
|
||||
#define strmov_overlapp(A,B) strmov(A,B)
|
||||
extern char *strmov_overlapp(char *dest, const char *src);
|
||||
/* Warning: the following is likely not to work: */
|
||||
#define strmake_overlapp(A,B,C) strmake(A,B,C)
|
||||
#endif
|
||||
|
||||
|
|
|
|||
|
|
@ -791,6 +791,9 @@ extern size_t my_b_gets(IO_CACHE *info, char *to, size_t max_length);
|
|||
extern my_off_t my_b_filelength(IO_CACHE *info);
|
||||
extern size_t my_b_printf(IO_CACHE *info, const char* fmt, ...);
|
||||
extern size_t my_b_vprintf(IO_CACHE *info, const char* fmt, va_list ap);
|
||||
extern int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val);
|
||||
extern int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
|
||||
extern my_bool open_cached_file(IO_CACHE *cache,const char *dir,
|
||||
const char *prefix, size_t cache_size,
|
||||
myf cache_myflags);
|
||||
|
|
|
|||
|
|
@ -46,7 +46,8 @@ mystringsobjects = strmov.lo strxmov.lo strxnmov.lo strnmov.lo \
|
|||
ctype-win1250ch.lo ctype-utf8.lo ctype-extra.lo \
|
||||
ctype-ucs2.lo ctype-gb2312.lo ctype-gbk.lo \
|
||||
ctype-sjis.lo ctype-tis620.lo ctype-ujis.lo \
|
||||
ctype-uca.lo xml.lo my_strtoll10.lo str_alloc.lo
|
||||
ctype-uca.lo xml.lo my_strtoll10.lo str_alloc.lo \
|
||||
strmov_overlapp.lo
|
||||
|
||||
mystringsextra= strto.c
|
||||
dbugobjects = dbug.lo # IT IS IN SAFEMALLOC.C sanity.lo
|
||||
|
|
|
|||
|
|
@ -132,9 +132,9 @@ IF(WITH_FEDERATED_STORAGE_ENGINE)
|
|||
ENDIF(WITH_FEDERATED_STORAGE_ENGINE)
|
||||
|
||||
IF(WITH_INNOBASE_STORAGE_ENGINE)
|
||||
INCLUDE(${CMAKE_SOURCE_DIR}/storage/innobase/CMakeLists.txt)
|
||||
INCLUDE(${CMAKE_SOURCE_DIR}/storage/xtradb/CMakeLists.txt)
|
||||
FOREACH(rpath ${INNOBASE_SOURCES})
|
||||
SET(LIB_SOURCES ${LIB_SOURCES} ../storage/innobase/${rpath})
|
||||
SET(LIB_SOURCES ${LIB_SOURCES} ../storage/xtradb/${rpath})
|
||||
ENDFOREACH(rpath)
|
||||
ENDIF(WITH_INNOBASE_STORAGE_ENGINE)
|
||||
|
||||
|
|
|
|||
26
mysql-test/include/innodb-index.inc
Normal file
26
mysql-test/include/innodb-index.inc
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
--eval create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb default charset=$charset
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique index (b);
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
show create table t1;
|
||||
alter table t1 add index (b);
|
||||
insert into t1 values(10,10,'kkk','iii');
|
||||
select * from t1;
|
||||
select * from t1 force index(b) order by b;
|
||||
explain select * from t1 force index(b) order by b;
|
||||
show create table t1;
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
insert into t1 values(11,11,'aaa','mmm');
|
||||
select * from t1;
|
||||
select * from t1 force index(b) order by b;
|
||||
select * from t1 force index(c) order by c;
|
||||
select * from t1 force index(d) order by d;
|
||||
explain select * from t1 force index(b) order by b;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
explain select * from t1 force index(d) order by d;
|
||||
show create table t1;
|
||||
check table t1;
|
||||
drop table t1;
|
||||
|
|
@ -12,7 +12,9 @@ BEGIN
|
|||
-- Dump all global variables except those
|
||||
-- that are supposed to change
|
||||
SELECT * FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
|
||||
WHERE variable_name != 'timestamp' and variable_name != "debug" order by variable_name;
|
||||
WHERE variable_name != 'timestamp' AND variable_name != "debug"
|
||||
AND variable_name != 'INNODB_IBUF_MAX_SIZE'
|
||||
ORDER BY variable_name;
|
||||
|
||||
-- Dump all databases, there should be none
|
||||
-- except those that was created during bootstrap
|
||||
|
|
|
|||
|
|
@ -86,6 +86,8 @@ explain select count(*) from t1 where v between 'a' and 'a ';
|
|||
--replace_column 9 #
|
||||
explain select count(*) from t1 where v between 'a' and 'a ' and v between 'a ' and 'b\n';
|
||||
|
||||
# Which duplicate entry triggers error is not deterministic.
|
||||
--replace_regex /Duplicate entry '[^']+' for key/Duplicate entry '{ ' for key/
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique(v);
|
||||
alter table t1 add key(v);
|
||||
|
|
|
|||
|
|
@ -970,6 +970,16 @@ sub collect_one_test_case {
|
|||
}
|
||||
}
|
||||
|
||||
if ( $tinfo->{'not_valgrind'} )
|
||||
{
|
||||
if ( $::opt_valgrind_mysqld )
|
||||
{
|
||||
$tinfo->{'skip'}= 1;
|
||||
$tinfo->{'comment'}= "Not compatible with Valgrind testing";
|
||||
return $tinfo;
|
||||
}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------
|
||||
# Find config file to use if not already selected in <testname>.opt file
|
||||
# ----------------------------------------------------------------------
|
||||
|
|
@ -1050,6 +1060,7 @@ my @tags=
|
|||
["include/ndb_master-slave.inc", "ndb_test", 1],
|
||||
["federated.inc", "federated_test", 1],
|
||||
["include/not_embedded.inc", "not_embedded", 1],
|
||||
["include/not_valgrind.inc", "not_valgrind", 1],
|
||||
);
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -224,7 +224,7 @@ my $opt_strace_client;
|
|||
our $opt_user = "root";
|
||||
|
||||
my $opt_valgrind= 0;
|
||||
my $opt_valgrind_mysqld= 0;
|
||||
our $opt_valgrind_mysqld= 0;
|
||||
my $opt_valgrind_mysqltest= 0;
|
||||
my @default_valgrind_args= ("--show-reachable=yes");
|
||||
my @valgrind_args;
|
||||
|
|
@ -1356,6 +1356,18 @@ sub command_line_setup {
|
|||
join(" ", @valgrind_args), "\"");
|
||||
}
|
||||
|
||||
# InnoDB does not bother to do individual de-allocations at exit. Instead it
|
||||
# relies on a custom allocator to track every allocation, and frees all at
|
||||
# once during exit.
|
||||
# In XtraDB, an option use-sys-malloc is introduced (and on by default) to
|
||||
# disable this (for performance). But this exposes Valgrind to all the
|
||||
# missing de-allocations, so we need to disable it to at least get
|
||||
# meaningful leak checking for the rest of the server.
|
||||
if ($opt_valgrind_mysqld)
|
||||
{
|
||||
push(@opt_extra_mysqld_opt, "--loose-skip-innodb-use-sys-malloc");
|
||||
}
|
||||
|
||||
mtr_report("Checking supported features...");
|
||||
|
||||
check_ndbcluster_support(\%mysqld_variables);
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ USE events_conn1_test2;
|
|||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
|
||||
COUNT(*)
|
||||
50
|
||||
SET @old_event_scheduler=@@event_scheduler;
|
||||
SET GLOBAL event_scheduler=on;
|
||||
DROP DATABASE events_conn1_test2;
|
||||
SET GLOBAL event_scheduler=off;
|
||||
|
|
@ -63,3 +64,4 @@ DROP TABLE fill_it1;
|
|||
DROP TABLE fill_it2;
|
||||
DROP TABLE fill_it3;
|
||||
DROP DATABASE events_test;
|
||||
SET GLOBAL event_scheduler=@old_event_scheduler;
|
||||
|
|
|
|||
|
|
@ -111,7 +111,7 @@ count(*)
|
|||
explain select count(*) from t1 where
|
||||
key1a = 2 and key1b is null and key2a = 2 and key2b is null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL 4 Using intersect(i1,i2); Using where; Using index
|
||||
1 SIMPLE t1 index_merge i1,i2 i1,i2 10,10 NULL 3 Using intersect(i1,i2); Using where; Using index
|
||||
select count(*) from t1 where
|
||||
key1a = 2 and key1b is null and key2a = 2 and key2b is null;
|
||||
count(*)
|
||||
|
|
@ -119,7 +119,7 @@ count(*)
|
|||
explain select count(*) from t1 where
|
||||
key1a = 2 and key1b is null and key3a = 2 and key3b is null;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL 4 Using intersect(i1,i3); Using where; Using index
|
||||
1 SIMPLE t1 index_merge i1,i3 i1,i3 10,10 NULL 3 Using intersect(i1,i3); Using where; Using index
|
||||
select count(*) from t1 where
|
||||
key1a = 2 and key1b is null and key3a = 2 and key3b is null;
|
||||
count(*)
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND
|
|||
table_name<>'ndb_binlog_index' AND
|
||||
table_name<>'ndb_apply_status' AND
|
||||
NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%');
|
||||
select * from v1;
|
||||
select * from v1 ORDER BY c COLLATE utf8_bin;
|
||||
c
|
||||
CHARACTER_SETS
|
||||
COLLATIONS
|
||||
|
|
@ -54,6 +54,19 @@ EVENTS
|
|||
FILES
|
||||
GLOBAL_STATUS
|
||||
GLOBAL_VARIABLES
|
||||
INNODB_BUFFER_POOL_PAGES
|
||||
INNODB_BUFFER_POOL_PAGES_BLOB
|
||||
INNODB_BUFFER_POOL_PAGES_INDEX
|
||||
INNODB_CMP
|
||||
INNODB_CMPMEM
|
||||
INNODB_CMPMEM_RESET
|
||||
INNODB_CMP_RESET
|
||||
INNODB_INDEX_STATS
|
||||
INNODB_LOCKS
|
||||
INNODB_LOCK_WAITS
|
||||
INNODB_RSEG
|
||||
INNODB_TABLE_STATS
|
||||
INNODB_TRX
|
||||
KEY_COLUMN_USAGE
|
||||
PARTITIONS
|
||||
PLUGINS
|
||||
|
|
@ -72,6 +85,7 @@ TABLE_PRIVILEGES
|
|||
TRIGGERS
|
||||
USER_PRIVILEGES
|
||||
VIEWS
|
||||
XTRADB_ENHANCEMENTS
|
||||
columns_priv
|
||||
db
|
||||
event
|
||||
|
|
@ -87,6 +101,11 @@ proc
|
|||
procs_priv
|
||||
servers
|
||||
slow_log
|
||||
t1
|
||||
t2
|
||||
t3
|
||||
t4
|
||||
t5
|
||||
tables_priv
|
||||
time_zone
|
||||
time_zone_leap_second
|
||||
|
|
@ -94,11 +113,6 @@ time_zone_name
|
|||
time_zone_transition
|
||||
time_zone_transition_type
|
||||
user
|
||||
t1
|
||||
t4
|
||||
t2
|
||||
t3
|
||||
t5
|
||||
v1
|
||||
select c,table_name from v1
|
||||
inner join information_schema.TABLES v2 on (v1.c=v2.table_name)
|
||||
|
|
@ -800,6 +814,8 @@ TABLES CREATE_TIME datetime
|
|||
TABLES UPDATE_TIME datetime
|
||||
TABLES CHECK_TIME datetime
|
||||
TRIGGERS CREATED datetime
|
||||
INNODB_TRX trx_started datetime
|
||||
INNODB_TRX trx_wait_started datetime
|
||||
event execute_at datetime
|
||||
event last_executed datetime
|
||||
event starts datetime
|
||||
|
|
@ -848,6 +864,9 @@ TABLES TABLE_NAME select
|
|||
TABLE_CONSTRAINTS TABLE_NAME select
|
||||
TABLE_PRIVILEGES TABLE_NAME select
|
||||
VIEWS TABLE_NAME select
|
||||
INNODB_BUFFER_POOL_PAGES_INDEX table_name select
|
||||
INNODB_INDEX_STATS table_name select
|
||||
INNODB_TABLE_STATS table_name select
|
||||
delete from mysql.user where user='mysqltest_4';
|
||||
delete from mysql.db where user='mysqltest_4';
|
||||
flush privileges;
|
||||
|
|
@ -1223,12 +1242,12 @@ DROP PROCEDURE p1;
|
|||
DROP USER mysql_bug20230@localhost;
|
||||
SELECT MAX(table_name) FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test');
|
||||
MAX(table_name)
|
||||
VIEWS
|
||||
XTRADB_ENHANCEMENTS
|
||||
SELECT table_name from information_schema.tables
|
||||
WHERE table_name=(SELECT MAX(table_name)
|
||||
FROM information_schema.tables WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test'));
|
||||
table_name
|
||||
VIEWS
|
||||
XTRADB_ENHANCEMENTS
|
||||
DROP TABLE IF EXISTS bug23037;
|
||||
DROP FUNCTION IF EXISTS get_value;
|
||||
SELECT COLUMN_NAME, MD5(COLUMN_DEFAULT), LENGTH(COLUMN_DEFAULT) FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME='bug23037';
|
||||
|
|
|
|||
|
|
@ -29,7 +29,21 @@ TABLE_PRIVILEGES
|
|||
TRIGGERS
|
||||
USER_PRIVILEGES
|
||||
VIEWS
|
||||
INNODB_BUFFER_POOL_PAGES
|
||||
PBXT_STATISTICS
|
||||
INNODB_CMP
|
||||
INNODB_RSEG
|
||||
XTRADB_ENHANCEMENTS
|
||||
INNODB_BUFFER_POOL_PAGES_INDEX
|
||||
INNODB_INDEX_STATS
|
||||
INNODB_TRX
|
||||
INNODB_CMP_RESET
|
||||
INNODB_LOCK_WAITS
|
||||
INNODB_CMPMEM_RESET
|
||||
INNODB_LOCKS
|
||||
INNODB_CMPMEM
|
||||
INNODB_TABLE_STATS
|
||||
INNODB_BUFFER_POOL_PAGES_BLOB
|
||||
SELECT t.table_name, c1.column_name
|
||||
FROM information_schema.tables t
|
||||
INNER JOIN
|
||||
|
|
@ -73,7 +87,21 @@ TABLE_PRIVILEGES TABLE_SCHEMA
|
|||
TRIGGERS TRIGGER_SCHEMA
|
||||
USER_PRIVILEGES GRANTEE
|
||||
VIEWS TABLE_SCHEMA
|
||||
INNODB_BUFFER_POOL_PAGES page_type
|
||||
PBXT_STATISTICS ID
|
||||
INNODB_CMP page_size
|
||||
INNODB_RSEG rseg_id
|
||||
XTRADB_ENHANCEMENTS name
|
||||
INNODB_BUFFER_POOL_PAGES_INDEX schema_name
|
||||
INNODB_INDEX_STATS table_name
|
||||
INNODB_TRX trx_id
|
||||
INNODB_CMP_RESET page_size
|
||||
INNODB_LOCK_WAITS requesting_trx_id
|
||||
INNODB_CMPMEM_RESET page_size
|
||||
INNODB_LOCKS lock_id
|
||||
INNODB_CMPMEM page_size
|
||||
INNODB_TABLE_STATS table_name
|
||||
INNODB_BUFFER_POOL_PAGES_BLOB space_id
|
||||
SELECT t.table_name, c1.column_name
|
||||
FROM information_schema.tables t
|
||||
INNER JOIN
|
||||
|
|
@ -117,7 +145,21 @@ TABLE_PRIVILEGES TABLE_SCHEMA
|
|||
TRIGGERS TRIGGER_SCHEMA
|
||||
USER_PRIVILEGES GRANTEE
|
||||
VIEWS TABLE_SCHEMA
|
||||
INNODB_BUFFER_POOL_PAGES page_type
|
||||
PBXT_STATISTICS ID
|
||||
INNODB_CMP page_size
|
||||
INNODB_RSEG rseg_id
|
||||
XTRADB_ENHANCEMENTS name
|
||||
INNODB_BUFFER_POOL_PAGES_INDEX schema_name
|
||||
INNODB_INDEX_STATS table_name
|
||||
INNODB_TRX trx_id
|
||||
INNODB_CMP_RESET page_size
|
||||
INNODB_LOCK_WAITS requesting_trx_id
|
||||
INNODB_CMPMEM_RESET page_size
|
||||
INNODB_LOCKS lock_id
|
||||
INNODB_CMPMEM page_size
|
||||
INNODB_TABLE_STATS table_name
|
||||
INNODB_BUFFER_POOL_PAGES_BLOB space_id
|
||||
select 1 as f1 from information_schema.tables where "CHARACTER_SETS"=
|
||||
(select cast(table_name as char) from information_schema.tables
|
||||
order by table_name limit 1) limit 1;
|
||||
|
|
@ -149,6 +191,19 @@ EVENTS information_schema.EVENTS 1
|
|||
FILES information_schema.FILES 1
|
||||
GLOBAL_STATUS information_schema.GLOBAL_STATUS 1
|
||||
GLOBAL_VARIABLES information_schema.GLOBAL_VARIABLES 1
|
||||
INNODB_BUFFER_POOL_PAGES information_schema.INNODB_BUFFER_POOL_PAGES 1
|
||||
INNODB_BUFFER_POOL_PAGES_BLOB information_schema.INNODB_BUFFER_POOL_PAGES_BLOB 1
|
||||
INNODB_BUFFER_POOL_PAGES_INDEX information_schema.INNODB_BUFFER_POOL_PAGES_INDEX 1
|
||||
INNODB_CMP information_schema.INNODB_CMP 1
|
||||
INNODB_CMPMEM information_schema.INNODB_CMPMEM 1
|
||||
INNODB_CMPMEM_RESET information_schema.INNODB_CMPMEM_RESET 1
|
||||
INNODB_CMP_RESET information_schema.INNODB_CMP_RESET 1
|
||||
INNODB_INDEX_STATS information_schema.INNODB_INDEX_STATS 1
|
||||
INNODB_LOCKS information_schema.INNODB_LOCKS 1
|
||||
INNODB_LOCK_WAITS information_schema.INNODB_LOCK_WAITS 1
|
||||
INNODB_RSEG information_schema.INNODB_RSEG 1
|
||||
INNODB_TABLE_STATS information_schema.INNODB_TABLE_STATS 1
|
||||
INNODB_TRX information_schema.INNODB_TRX 1
|
||||
KEY_COLUMN_USAGE information_schema.KEY_COLUMN_USAGE 1
|
||||
PARTITIONS information_schema.PARTITIONS 1
|
||||
PBXT_STATISTICS information_schema.PBXT_STATISTICS 1
|
||||
|
|
@ -168,6 +223,7 @@ TABLE_PRIVILEGES information_schema.TABLE_PRIVILEGES 1
|
|||
TRIGGERS information_schema.TRIGGERS 1
|
||||
USER_PRIVILEGES information_schema.USER_PRIVILEGES 1
|
||||
VIEWS information_schema.VIEWS 1
|
||||
XTRADB_ENHANCEMENTS information_schema.XTRADB_ENHANCEMENTS 1
|
||||
Database: information_schema
|
||||
+---------------------------------------+
|
||||
| Tables |
|
||||
|
|
@ -200,7 +256,21 @@ Database: information_schema
|
|||
| TRIGGERS |
|
||||
| USER_PRIVILEGES |
|
||||
| VIEWS |
|
||||
| INNODB_BUFFER_POOL_PAGES |
|
||||
| PBXT_STATISTICS |
|
||||
| INNODB_CMP |
|
||||
| INNODB_RSEG |
|
||||
| XTRADB_ENHANCEMENTS |
|
||||
| INNODB_BUFFER_POOL_PAGES_INDEX |
|
||||
| INNODB_INDEX_STATS |
|
||||
| INNODB_TRX |
|
||||
| INNODB_CMP_RESET |
|
||||
| INNODB_LOCK_WAITS |
|
||||
| INNODB_CMPMEM_RESET |
|
||||
| INNODB_LOCKS |
|
||||
| INNODB_CMPMEM |
|
||||
| INNODB_TABLE_STATS |
|
||||
| INNODB_BUFFER_POOL_PAGES_BLOB |
|
||||
+---------------------------------------+
|
||||
Database: INFORMATION_SCHEMA
|
||||
+---------------------------------------+
|
||||
|
|
@ -234,7 +304,21 @@ Database: INFORMATION_SCHEMA
|
|||
| TRIGGERS |
|
||||
| USER_PRIVILEGES |
|
||||
| VIEWS |
|
||||
| INNODB_BUFFER_POOL_PAGES |
|
||||
| PBXT_STATISTICS |
|
||||
| INNODB_CMP |
|
||||
| INNODB_RSEG |
|
||||
| XTRADB_ENHANCEMENTS |
|
||||
| INNODB_BUFFER_POOL_PAGES_INDEX |
|
||||
| INNODB_INDEX_STATS |
|
||||
| INNODB_TRX |
|
||||
| INNODB_CMP_RESET |
|
||||
| INNODB_LOCK_WAITS |
|
||||
| INNODB_CMPMEM_RESET |
|
||||
| INNODB_LOCKS |
|
||||
| INNODB_CMPMEM |
|
||||
| INNODB_TABLE_STATS |
|
||||
| INNODB_BUFFER_POOL_PAGES_BLOB |
|
||||
+---------------------------------------+
|
||||
Wildcard: inf_rmation_schema
|
||||
+--------------------+
|
||||
|
|
@ -244,5 +328,5 @@ Wildcard: inf_rmation_schema
|
|||
+--------------------+
|
||||
SELECT table_schema, count(*) FROM information_schema.TABLES WHERE table_schema IN ('mysql', 'INFORMATION_SCHEMA', 'test', 'mysqltest') AND table_name<>'ndb_binlog_index' AND table_name<>'ndb_apply_status' GROUP BY TABLE_SCHEMA;
|
||||
table_schema count(*)
|
||||
information_schema 29
|
||||
information_schema 43
|
||||
mysql 22
|
||||
|
|
|
|||
2
mysql-test/r/innodb-analyze.result
Normal file
2
mysql-test/r/innodb-analyze.result
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
Variable_name Value
|
||||
innodb_stats_sample_pages 1
|
||||
|
|
@ -581,11 +581,10 @@ c1
|
|||
DROP TABLE t1;
|
||||
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
|
||||
SET @@INSERT_ID=1;
|
||||
SHOW VARIABLES LIKE "%auto_inc%";
|
||||
SHOW VARIABLES LIKE "auto_inc%";
|
||||
Variable_name Value
|
||||
auto_increment_increment 1
|
||||
auto_increment_offset 1
|
||||
pbxt_auto_increment_mode 0
|
||||
CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES(NULL, 1);
|
||||
INSERT INTO t1 VALUES(NULL, 2);
|
||||
|
|
|
|||
1137
mysql-test/r/innodb-index.result
Normal file
1137
mysql-test/r/innodb-index.result
Normal file
File diff suppressed because it is too large
Load diff
116
mysql-test/r/innodb-index_ucs2.result
Normal file
116
mysql-test/r/innodb-index_ucs2.result
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb default charset=ucs2;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add unique index (b);
|
||||
ERROR 23000: Duplicate entry '2' for key 'b'
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=ucs2
|
||||
alter table t1 add index (b);
|
||||
insert into t1 values(10,10,'kkk','iii');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
select * from t1 force index(b) order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
explain select * from t1 force index(b) order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 6
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
KEY `b` (`b`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=ucs2
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
insert into t1 values(11,11,'aaa','mmm');
|
||||
select * from t1;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
11 11 aaa mmm
|
||||
select * from t1 force index(b) order by b;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
11 11 aaa mmm
|
||||
select * from t1 force index(c) order by c;
|
||||
a b c d
|
||||
11 11 aaa mmm
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
select * from t1 force index(d) order by d;
|
||||
a b c d
|
||||
1 1 ab ab
|
||||
2 2 ac ac
|
||||
3 2 ad ad
|
||||
4 4 afe afe
|
||||
8 9 fff fff
|
||||
10 10 kkk iii
|
||||
11 11 aaa mmm
|
||||
explain select * from t1 force index(b) order by b;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL b 5 NULL 7
|
||||
explain select * from t1 force index(c) order by c;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL c 21 NULL 7
|
||||
explain select * from t1 force index(d) order by d;
|
||||
id select_type table type possible_keys key key_len ref rows Extra
|
||||
1 SIMPLE t1 index NULL d 43 NULL 7
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
`a` int(11) NOT NULL,
|
||||
`b` int(11) DEFAULT NULL,
|
||||
`c` char(10) DEFAULT NULL,
|
||||
`d` varchar(20) DEFAULT NULL,
|
||||
PRIMARY KEY (`a`),
|
||||
UNIQUE KEY `c` (`c`),
|
||||
KEY `b` (`b`),
|
||||
KEY `d` (`d`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=ucs2
|
||||
check table t1;
|
||||
Table Op Msg_type Msg_text
|
||||
test.t1 check status OK
|
||||
drop table t1;
|
||||
38
mysql-test/r/innodb-timeout.result
Normal file
38
mysql-test/r/innodb-timeout.result
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
set global innodb_lock_wait_timeout=42;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
@@innodb_lock_wait_timeout
|
||||
42
|
||||
set innodb_lock_wait_timeout=1;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
@@innodb_lock_wait_timeout
|
||||
1
|
||||
select @@innodb_lock_wait_timeout;
|
||||
@@innodb_lock_wait_timeout
|
||||
42
|
||||
set global innodb_lock_wait_timeout=347;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
@@innodb_lock_wait_timeout
|
||||
42
|
||||
set innodb_lock_wait_timeout=1;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
@@innodb_lock_wait_timeout
|
||||
1
|
||||
select @@innodb_lock_wait_timeout;
|
||||
@@innodb_lock_wait_timeout
|
||||
347
|
||||
create table t1(a int primary key)engine=innodb;
|
||||
begin;
|
||||
insert into t1 values(1),(2),(3);
|
||||
select * from t1 for update;
|
||||
commit;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
begin;
|
||||
insert into t1 values(4);
|
||||
select * from t1 for update;
|
||||
commit;
|
||||
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
|
||||
drop table t1;
|
||||
set global innodb_lock_wait_timeout=50;
|
||||
48
mysql-test/r/innodb-use-sys-malloc.result
Normal file
48
mysql-test/r/innodb-use-sys-malloc.result
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
@@GLOBAL.innodb_use_sys_malloc
|
||||
1
|
||||
1 Expected
|
||||
SET @@GLOBAL.innodb_use_sys_malloc=0;
|
||||
ERROR HY000: Variable 'innodb_use_sys_malloc' is a read only variable
|
||||
Expected error 'Read only variable'
|
||||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
@@GLOBAL.innodb_use_sys_malloc
|
||||
1
|
||||
1 Expected
|
||||
drop table if exists t1;
|
||||
create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
|
||||
insert into t1 values (1),(2),(3),(4),(5),(6),(7);
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
drop table t1;
|
||||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
@@GLOBAL.innodb_use_sys_malloc
|
||||
1
|
||||
1 Expected
|
||||
SET @@GLOBAL.innodb_use_sys_malloc=0;
|
||||
ERROR HY000: Variable 'innodb_use_sys_malloc' is a read only variable
|
||||
Expected error 'Read only variable'
|
||||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
@@GLOBAL.innodb_use_sys_malloc
|
||||
1
|
||||
1 Expected
|
||||
drop table if exists t1;
|
||||
create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
|
||||
insert into t1 values (1),(2),(3),(4),(5),(6),(7);
|
||||
select * from t1;
|
||||
a
|
||||
1
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
7
|
||||
drop table t1;
|
||||
421
mysql-test/r/innodb-zip.result
Normal file
421
mysql-test/r/innodb-zip.result
Normal file
|
|
@ -0,0 +1,421 @@
|
|||
set global innodb_file_per_table=off;
|
||||
set global innodb_file_format=`0`;
|
||||
create table t0(a int primary key) engine=innodb row_format=compressed;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
|
||||
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
|
||||
create table t00(a int primary key) engine=innodb
|
||||
key_block_size=4 row_format=compressed;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=4.
|
||||
Warning 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
|
||||
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
|
||||
create table t1(a int primary key) engine=innodb row_format=dynamic;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table.
|
||||
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
|
||||
create table t2(a int primary key) engine=innodb row_format=redundant;
|
||||
create table t3(a int primary key) engine=innodb row_format=compact;
|
||||
create table t4(a int primary key) engine=innodb key_block_size=9;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=9.
|
||||
create table t5(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=redundant;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1.
|
||||
set global innodb_file_per_table=on;
|
||||
create table t6(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=redundant;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1.
|
||||
set global innodb_file_format=`1`;
|
||||
create table t7(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=redundant;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
|
||||
create table t8(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=fixed;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
|
||||
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
|
||||
create table t9(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=compact;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
|
||||
create table t10(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=dynamic;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=1 unless ROW_FORMAT=COMPRESSED.
|
||||
create table t11(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=compressed;
|
||||
create table t12(a int primary key) engine=innodb
|
||||
key_block_size=1;
|
||||
create table t13(a int primary key) engine=innodb
|
||||
row_format=compressed;
|
||||
create table t14(a int primary key) engine=innodb key_block_size=9;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=9.
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t0 Compact
|
||||
test t00 Compact
|
||||
test t1 Compact
|
||||
test t10 Dynamic
|
||||
test t11 Compressed
|
||||
test t12 Compressed
|
||||
test t13 Compressed
|
||||
test t14 Compact
|
||||
test t2 Redundant
|
||||
test t3 Compact
|
||||
test t4 Compact
|
||||
test t5 Redundant
|
||||
test t6 Redundant
|
||||
test t7 Redundant
|
||||
test t8 Compact
|
||||
test t9 Compact
|
||||
drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14;
|
||||
alter table t1 key_block_size=0;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0.
|
||||
alter table t1 row_format=dynamic;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t1 Dynamic
|
||||
alter table t1 row_format=compact;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t1 Compact
|
||||
alter table t1 row_format=redundant;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t1 Redundant
|
||||
drop table t1;
|
||||
create table t1(a int not null, b text, index(b(10))) engine=innodb
|
||||
key_block_size=1;
|
||||
create table t2(b text)engine=innodb;
|
||||
insert into t2 values(concat('1abcdefghijklmnopqrstuvwxyz', repeat('A',5000)));
|
||||
insert into t1 select 1, b from t2;
|
||||
commit;
|
||||
begin;
|
||||
update t1 set b=repeat('B',100);
|
||||
select a,left(b,40) from t1 natural join t2;
|
||||
a left(b,40)
|
||||
1 1abcdefghijklmnopqrstuvwxyzAAAAAAAAAAAAA
|
||||
rollback;
|
||||
select a,left(b,40) from t1 natural join t2;
|
||||
a left(b,40)
|
||||
1 1abcdefghijklmnopqrstuvwxyzAAAAAAAAAAAAA
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t1 Compressed
|
||||
test t2 Compact
|
||||
drop table t1,t2;
|
||||
SET SESSION innodb_strict_mode = off;
|
||||
CREATE TABLE t1(
|
||||
c TEXT NOT NULL, d TEXT NOT NULL,
|
||||
PRIMARY KEY (c(767),d(767)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
|
||||
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
|
||||
CREATE TABLE t1(
|
||||
c TEXT NOT NULL, d TEXT NOT NULL,
|
||||
PRIMARY KEY (c(767),d(767)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2 CHARSET=ASCII;
|
||||
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
|
||||
CREATE TABLE t1(
|
||||
c TEXT NOT NULL, d TEXT NOT NULL,
|
||||
PRIMARY KEY (c(767),d(767)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 CHARSET=ASCII;
|
||||
drop table t1;
|
||||
CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
|
||||
ERROR 42000: Row size too large. The maximum row size for the used table type, not counting BLOBs, is 8126. You have to change some columns to TEXT or BLOBs
|
||||
CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
|
||||
INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512));
|
||||
DROP TABLE t1;
|
||||
create table t1( c1 int not null, c2 blob, c3 blob, c4 blob,
|
||||
primary key(c1, c2(22), c3(22)))
|
||||
engine = innodb row_format = dynamic;
|
||||
begin;
|
||||
insert into t1 values(1, repeat('A', 20000), repeat('B', 20000),
|
||||
repeat('C', 20000));
|
||||
update t1 set c3 = repeat('D', 20000) where c1 = 1;
|
||||
commit;
|
||||
select count(*) from t1 where c2 = repeat('A', 20000);
|
||||
count(*)
|
||||
1
|
||||
select count(*) from t1 where c3 = repeat('D', 20000);
|
||||
count(*)
|
||||
1
|
||||
select count(*) from t1 where c4 = repeat('C', 20000);
|
||||
count(*)
|
||||
1
|
||||
update t1 set c3 = repeat('E', 20000) where c1 = 1;
|
||||
drop table t1;
|
||||
set global innodb_file_format=`0`;
|
||||
select @@innodb_file_format;
|
||||
@@innodb_file_format
|
||||
Antelope
|
||||
set global innodb_file_format=`1`;
|
||||
select @@innodb_file_format;
|
||||
@@innodb_file_format
|
||||
Barracuda
|
||||
set global innodb_file_format=`2`;
|
||||
ERROR HY000: Incorrect arguments to SET
|
||||
set global innodb_file_format=`-1`;
|
||||
ERROR HY000: Incorrect arguments to SET
|
||||
set global innodb_file_format=`Antelope`;
|
||||
set global innodb_file_format=`Barracuda`;
|
||||
set global innodb_file_format=`Cheetah`;
|
||||
ERROR HY000: Incorrect arguments to SET
|
||||
set global innodb_file_format=`abc`;
|
||||
ERROR HY000: Incorrect arguments to SET
|
||||
set global innodb_file_format=`1a`;
|
||||
ERROR HY000: Incorrect arguments to SET
|
||||
set global innodb_file_format=``;
|
||||
ERROR HY000: Incorrect arguments to SET
|
||||
set global innodb_file_per_table = on;
|
||||
set global innodb_file_format = `1`;
|
||||
set innodb_strict_mode = off;
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 0;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: ignoring KEY_BLOCK_SIZE=0.
|
||||
drop table t1;
|
||||
set innodb_strict_mode = on;
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 0;
|
||||
ERROR HY000: Can't create table 'test.t1' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 0. Valid values are [1, 2, 4, 8, 16]
|
||||
Error 1005 Can't create table 'test.t1' (errno: 1478)
|
||||
create table t2 (id int primary key) engine = innodb key_block_size = 9;
|
||||
ERROR HY000: Can't create table 'test.t2' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
|
||||
Error 1005 Can't create table 'test.t2' (errno: 1478)
|
||||
create table t3 (id int primary key) engine = innodb key_block_size = 1;
|
||||
create table t4 (id int primary key) engine = innodb key_block_size = 2;
|
||||
create table t5 (id int primary key) engine = innodb key_block_size = 4;
|
||||
create table t6 (id int primary key) engine = innodb key_block_size = 8;
|
||||
create table t7 (id int primary key) engine = innodb key_block_size = 16;
|
||||
create table t8 (id int primary key) engine = innodb row_format = compressed;
|
||||
create table t9 (id int primary key) engine = innodb row_format = dynamic;
|
||||
create table t10(id int primary key) engine = innodb row_format = compact;
|
||||
create table t11(id int primary key) engine = innodb row_format = redundant;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t10 Compact
|
||||
test t11 Redundant
|
||||
test t3 Compressed
|
||||
test t4 Compressed
|
||||
test t5 Compressed
|
||||
test t6 Compressed
|
||||
test t7 Compressed
|
||||
test t8 Compressed
|
||||
test t9 Dynamic
|
||||
drop table t3, t4, t5, t6, t7, t8, t9, t10, t11;
|
||||
create table t1 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = compressed;
|
||||
create table t2 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = redundant;
|
||||
ERROR HY000: Can't create table 'test.t2' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE.
|
||||
Error 1005 Can't create table 'test.t2' (errno: 1478)
|
||||
create table t3 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = compact;
|
||||
ERROR HY000: Can't create table 'test.t3' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE.
|
||||
Error 1005 Can't create table 'test.t3' (errno: 1478)
|
||||
create table t4 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = dynamic;
|
||||
ERROR HY000: Can't create table 'test.t4' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE.
|
||||
Error 1005 Can't create table 'test.t4' (errno: 1478)
|
||||
create table t5 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = default;
|
||||
ERROR HY000: Can't create table 'test.t5' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE.
|
||||
Error 1005 Can't create table 'test.t5' (errno: 1478)
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t1 Compressed
|
||||
drop table t1;
|
||||
create table t1 (id int primary key) engine = innodb
|
||||
key_block_size = 9 row_format = redundant;
|
||||
ERROR HY000: Can't create table 'test.t1' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
|
||||
Error 1478 InnoDB: cannot specify ROW_FORMAT = REDUNDANT with KEY_BLOCK_SIZE.
|
||||
Error 1005 Can't create table 'test.t1' (errno: 1478)
|
||||
create table t2 (id int primary key) engine = innodb
|
||||
key_block_size = 9 row_format = compact;
|
||||
ERROR HY000: Can't create table 'test.t2' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
|
||||
Error 1478 InnoDB: cannot specify ROW_FORMAT = COMPACT with KEY_BLOCK_SIZE.
|
||||
Error 1005 Can't create table 'test.t2' (errno: 1478)
|
||||
create table t2 (id int primary key) engine = innodb
|
||||
key_block_size = 9 row_format = dynamic;
|
||||
ERROR HY000: Can't create table 'test.t2' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: invalid KEY_BLOCK_SIZE = 9. Valid values are [1, 2, 4, 8, 16]
|
||||
Error 1478 InnoDB: cannot specify ROW_FORMAT = DYNAMIC with KEY_BLOCK_SIZE.
|
||||
Error 1005 Can't create table 'test.t2' (errno: 1478)
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
set global innodb_file_per_table = off;
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 1;
|
||||
ERROR HY000: Can't create table 'test.t1' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Error 1005 Can't create table 'test.t1' (errno: 1478)
|
||||
create table t2 (id int primary key) engine = innodb key_block_size = 2;
|
||||
ERROR HY000: Can't create table 'test.t2' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Error 1005 Can't create table 'test.t2' (errno: 1478)
|
||||
create table t3 (id int primary key) engine = innodb key_block_size = 4;
|
||||
ERROR HY000: Can't create table 'test.t3' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Error 1005 Can't create table 'test.t3' (errno: 1478)
|
||||
create table t4 (id int primary key) engine = innodb key_block_size = 8;
|
||||
ERROR HY000: Can't create table 'test.t4' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Error 1005 Can't create table 'test.t4' (errno: 1478)
|
||||
create table t5 (id int primary key) engine = innodb key_block_size = 16;
|
||||
ERROR HY000: Can't create table 'test.t5' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
|
||||
Error 1005 Can't create table 'test.t5' (errno: 1478)
|
||||
create table t6 (id int primary key) engine = innodb row_format = compressed;
|
||||
ERROR HY000: Can't create table 'test.t6' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
|
||||
Error 1005 Can't create table 'test.t6' (errno: 1478)
|
||||
create table t7 (id int primary key) engine = innodb row_format = dynamic;
|
||||
ERROR HY000: Can't create table 'test.t7' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_per_table.
|
||||
Error 1005 Can't create table 'test.t7' (errno: 1478)
|
||||
create table t8 (id int primary key) engine = innodb row_format = compact;
|
||||
create table t9 (id int primary key) engine = innodb row_format = redundant;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t8 Compact
|
||||
test t9 Redundant
|
||||
drop table t8, t9;
|
||||
set global innodb_file_per_table = on;
|
||||
set global innodb_file_format = `0`;
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 1;
|
||||
ERROR HY000: Can't create table 'test.t1' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Error 1005 Can't create table 'test.t1' (errno: 1478)
|
||||
create table t2 (id int primary key) engine = innodb key_block_size = 2;
|
||||
ERROR HY000: Can't create table 'test.t2' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Error 1005 Can't create table 'test.t2' (errno: 1478)
|
||||
create table t3 (id int primary key) engine = innodb key_block_size = 4;
|
||||
ERROR HY000: Can't create table 'test.t3' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Error 1005 Can't create table 'test.t3' (errno: 1478)
|
||||
create table t4 (id int primary key) engine = innodb key_block_size = 8;
|
||||
ERROR HY000: Can't create table 'test.t4' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Error 1005 Can't create table 'test.t4' (errno: 1478)
|
||||
create table t5 (id int primary key) engine = innodb key_block_size = 16;
|
||||
ERROR HY000: Can't create table 'test.t5' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
|
||||
Error 1005 Can't create table 'test.t5' (errno: 1478)
|
||||
create table t6 (id int primary key) engine = innodb row_format = compressed;
|
||||
ERROR HY000: Can't create table 'test.t6' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope.
|
||||
Error 1005 Can't create table 'test.t6' (errno: 1478)
|
||||
create table t7 (id int primary key) engine = innodb row_format = dynamic;
|
||||
ERROR HY000: Can't create table 'test.t7' (errno: 1478)
|
||||
show errors;
|
||||
Level Code Message
|
||||
Error 1478 InnoDB: ROW_FORMAT=DYNAMIC requires innodb_file_format > Antelope.
|
||||
Error 1005 Can't create table 'test.t7' (errno: 1478)
|
||||
create table t8 (id int primary key) engine = innodb row_format = compact;
|
||||
create table t9 (id int primary key) engine = innodb row_format = redundant;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
table_schema table_name row_format
|
||||
test t8 Compact
|
||||
test t9 Redundant
|
||||
drop table t8, t9;
|
||||
set global innodb_file_per_table=0;
|
||||
set global innodb_file_format=Antelope;
|
||||
set global innodb_file_per_table=on;
|
||||
set global innodb_file_format=`Barracuda`;
|
||||
set global innodb_file_format_check=`Antelope`;
|
||||
create table normal_table (
|
||||
c1 int
|
||||
) engine = innodb;
|
||||
select @@innodb_file_format_check;
|
||||
@@innodb_file_format_check
|
||||
Antelope
|
||||
create table zip_table (
|
||||
c1 int
|
||||
) engine = innodb key_block_size = 8;
|
||||
select @@innodb_file_format_check;
|
||||
@@innodb_file_format_check
|
||||
Barracuda
|
||||
set global innodb_file_format_check=`Antelope`;
|
||||
select @@innodb_file_format_check;
|
||||
@@innodb_file_format_check
|
||||
Antelope
|
||||
show table status;
|
||||
select @@innodb_file_format_check;
|
||||
@@innodb_file_format_check
|
||||
Barracuda
|
||||
drop table normal_table, zip_table;
|
||||
|
|
@ -1508,7 +1508,7 @@ t2 CREATE TABLE `t2` (
|
|||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop index id2 on t2;
|
||||
drop index id on t2;
|
||||
Got one of the listed errors
|
||||
ERROR HY000: Cannot drop index 'id': needed in a foreign key constraint
|
||||
show create table t2;
|
||||
Table Create Table
|
||||
t2 CREATE TABLE `t2` (
|
||||
|
|
@ -1738,7 +1738,7 @@ count(*)
|
|||
drop table t1;
|
||||
show status like "Innodb_buffer_pool_pages_total";
|
||||
Variable_name Value
|
||||
Innodb_buffer_pool_pages_total 512
|
||||
Innodb_buffer_pool_pages_total 511
|
||||
show status like "Innodb_page_size";
|
||||
Variable_name Value
|
||||
Innodb_page_size 16384
|
||||
|
|
@ -1784,7 +1784,7 @@ innodb_sync_spin_loops 20
|
|||
SET @old_innodb_thread_concurrency= @@global.innodb_thread_concurrency;
|
||||
show variables like "innodb_thread_concurrency";
|
||||
Variable_name Value
|
||||
innodb_thread_concurrency 8
|
||||
innodb_thread_concurrency 0
|
||||
set global innodb_thread_concurrency=1001;
|
||||
Warnings:
|
||||
Warning 1292 Truncated incorrect thread_concurrency value: '1001'
|
||||
|
|
@ -2377,6 +2377,8 @@ t1 CREATE TABLE `t1` (
|
|||
) ENGINE=InnoDB DEFAULT CHARSET=latin1
|
||||
drop table t1;
|
||||
create table t1 (v varchar(10), c char(10)) row_format=fixed;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
|
||||
show create table t1;
|
||||
Table Create Table
|
||||
t1 CREATE TABLE `t1` (
|
||||
|
|
@ -3190,6 +3192,7 @@ t1 CREATE TABLE `t1` (
|
|||
CONSTRAINT `t1_t2` FOREIGN KEY (`id`) REFERENCES `t2` (`id`)
|
||||
) ENGINE=InnoDB AUTO_INCREMENT=349 DEFAULT CHARSET=latin1
|
||||
DROP TABLE t1,t2;
|
||||
set innodb_strict_mode=on;
|
||||
CREATE TABLE t1 (
|
||||
c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255),
|
||||
c05 CHAR(255), c06 CHAR(255), c07 CHAR(255), c08 CHAR(255),
|
||||
|
|
|
|||
|
|
@ -1,8 +1,4 @@
|
|||
SELECT f4, f8 FROM bug34300;
|
||||
f4 f8
|
||||
xxx zzz
|
||||
ALTER TABLE bug34300 ADD COLUMN (f10 INT);
|
||||
SELECT f4, f8 FROM bug34300;
|
||||
f4 f8
|
||||
xxx zzz
|
||||
DROP TABLE bug34300;
|
||||
|
|
|
|||
5
mysql-test/r/innodb_bug36169.result
Normal file
5
mysql-test/r/innodb_bug36169.result
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
set @old_innodb_file_per_table=@@innodb_file_per_table;
|
||||
set @old_innodb_file_format=@@innodb_file_format;
|
||||
set @old_innodb_file_format_check=@@innodb_file_format_check;
|
||||
SET GLOBAL innodb_file_format='Barracuda';
|
||||
SET GLOBAL innodb_file_per_table=ON;
|
||||
1
mysql-test/r/innodb_bug36172.result
Normal file
1
mysql-test/r/innodb_bug36172.result
Normal file
|
|
@ -0,0 +1 @@
|
|||
SET storage_engine=InnoDB;
|
||||
4
mysql-test/r/innodb_bug40360.result
Normal file
4
mysql-test/r/innodb_bug40360.result
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
SET TX_ISOLATION='READ-COMMITTED';
|
||||
CREATE TABLE bug40360 (a INT) engine=innodb;
|
||||
INSERT INTO bug40360 VALUES (1);
|
||||
DROP TABLE bug40360;
|
||||
4
mysql-test/r/innodb_bug41904.result
Normal file
4
mysql-test/r/innodb_bug41904.result
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
CREATE TABLE bug41904 (id INT PRIMARY KEY, uniquecol CHAR(15)) ENGINE=InnoDB;
|
||||
INSERT INTO bug41904 VALUES (1,NULL), (2,NULL);
|
||||
CREATE UNIQUE INDEX ui ON bug41904 (uniquecol);
|
||||
DROP TABLE bug41904;
|
||||
23
mysql-test/r/innodb_information_schema.result
Normal file
23
mysql-test/r/innodb_information_schema.result
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
lock_mode lock_type lock_table lock_index lock_rec lock_data
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 2 '1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc'''''
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 3 '2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""'
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\'
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 5 '4', 'abc', '\0abc', 'abc\0', 'a\0bc', 'a\0bc\0', 'a\0bc\0\0'
|
||||
X RECORD `test`.`t_min` `PRIMARY` 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
|
||||
X RECORD `test`.`t_min` `PRIMARY` 2 -128, 0, -32768, 0, -8388608, 0, -2147483648, 0, -9223372036854775808, 0
|
||||
X RECORD `test`.`t_max` `PRIMARY` 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
|
||||
X RECORD `test`.`t_max` `PRIMARY` 2 127, 255, 32767, 65535, 8388607, 16777215, 2147483647, 4294967295, 9223372036854775807, 18446744073709551615
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 1 supremum pseudo-record
|
||||
X RECORD `test`.```t'\"_str` `PRIMARY` 1 supremum pseudo-record
|
||||
lock_table COUNT(*)
|
||||
`test`.`t_max` 2
|
||||
`test`.`t_min` 2
|
||||
`test`.```t'\"_str` 10
|
||||
lock_table COUNT(*)
|
||||
"test"."t_max" 2
|
||||
"test"."t_min" 2
|
||||
"test"."`t'\""_str" 10
|
||||
5
mysql-test/r/innodb_xtradb_bug317074.result
Normal file
5
mysql-test/r/innodb_xtradb_bug317074.result
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
SET @old_innodb_file_format=@@innodb_file_format;
|
||||
SET @old_innodb_file_per_table=@@innodb_file_per_table;
|
||||
SET @old_innodb_file_format_check=@@innodb_file_format_check;
|
||||
SET GLOBAL innodb_file_format='Barracuda';
|
||||
SET GLOBAL innodb_file_per_table=ON;
|
||||
|
|
@ -1,4 +1,9 @@
|
|||
#
|
||||
# We need big packets.
|
||||
#
|
||||
SET @old_global_max_allowed_packet=@@global.max_allowed_packet;
|
||||
SET @@global.max_allowed_packet= 1024*1024*1024;
|
||||
#
|
||||
# Preparatory cleanup.
|
||||
#
|
||||
DROP TABLE IF EXISTS t1;
|
||||
|
|
@ -7,10 +12,6 @@ DROP TABLE IF EXISTS t1;
|
|||
#
|
||||
SET timestamp=1000000000;
|
||||
#
|
||||
# We need big packets.
|
||||
#
|
||||
SET @@global.max_allowed_packet= 1024*1024*1024;
|
||||
#
|
||||
# Delete all existing binary logs.
|
||||
#
|
||||
RESET MASTER;
|
||||
|
|
@ -71,4 +72,5 @@ FLUSH LOGS;
|
|||
# Cleanup.
|
||||
#
|
||||
DROP TABLE t1;
|
||||
SET @@global.max_allowed_packet=@old_global_max_allowed_packet;
|
||||
remove_file $MYSQLTEST_VARDIR/tmp/mysqlbinlog_big_1.out
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ Table Checksum
|
|||
test.t1 4108368782
|
||||
drop table if exists t1;
|
||||
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
|
||||
insert into t1 values(null, null), (1, "hello");
|
||||
checksum table t1;
|
||||
Table Checksum
|
||||
|
|
|
|||
|
|
@ -72,6 +72,8 @@ Table Checksum
|
|||
test.t1 3885665021
|
||||
drop table if exists t1;
|
||||
create table t1 (a int null, v varchar(100)) engine=innodb checksum=0 row_format=fixed;
|
||||
Warnings:
|
||||
Warning 1478 InnoDB: assuming ROW_FORMAT=COMPACT.
|
||||
insert into t1 values(null, null), (1, "hello");
|
||||
checksum table t1;
|
||||
Table Checksum
|
||||
|
|
|
|||
|
|
@ -1,20 +1,20 @@
|
|||
set session transaction_prealloc_size=1024*1024*1024*1;
|
||||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root localhost test Query 0 NULL show processlist
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
TRUE
|
||||
1
|
||||
set session transaction_prealloc_size=1024*1024*1024*2;
|
||||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root localhost test Query 0 NULL show processlist
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
TRUE
|
||||
1
|
||||
set session transaction_prealloc_size=1024*1024*1024*3;
|
||||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root localhost test Query 0 NULL show processlist
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
TRUE
|
||||
1
|
||||
set session transaction_prealloc_size=1024*1024*1024*4;
|
||||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root localhost test Query 0 NULL show processlist
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
TRUE
|
||||
1
|
||||
set session transaction_prealloc_size=1024*1024*1024*5;
|
||||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root localhost test Query 0 NULL show processlist
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
TRUE
|
||||
1
|
||||
|
|
|
|||
|
|
@ -61,6 +61,7 @@ while ($1)
|
|||
}
|
||||
--enable_query_log
|
||||
SELECT COUNT(*) FROM INFORMATION_SCHEMA.EVENTS WHERE EVENT_SCHEMA='events_conn1_test2';
|
||||
SET @old_event_scheduler=@@event_scheduler;
|
||||
SET GLOBAL event_scheduler=on;
|
||||
--sleep 2.5
|
||||
DROP DATABASE events_conn1_test2;
|
||||
|
|
@ -135,3 +136,6 @@ DROP USER event_user3@localhost;
|
|||
#
|
||||
|
||||
DROP DATABASE events_test;
|
||||
|
||||
# Cleanup
|
||||
SET GLOBAL event_scheduler=@old_event_scheduler;
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ create view v1 (c) as
|
|||
table_name<>'ndb_binlog_index' AND
|
||||
table_name<>'ndb_apply_status' AND
|
||||
NOT (table_schema = 'INFORMATION_SCHEMA' AND table_name LIKE 'PBXT_%');
|
||||
select * from v1;
|
||||
select * from v1 ORDER BY c COLLATE utf8_bin;
|
||||
|
||||
select c,table_name from v1
|
||||
inner join information_schema.TABLES v2 on (v1.c=v2.table_name)
|
||||
|
|
|
|||
65
mysql-test/t/innodb-analyze.test
Normal file
65
mysql-test/t/innodb-analyze.test
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
#
|
||||
# Test that mysqld does not crash when running ANALYZE TABLE with
|
||||
# different values of the parameter innodb_stats_sample_pages.
|
||||
#
|
||||
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
# we care only that the following SQL commands do not produce errors
|
||||
# and do not crash the server
|
||||
-- disable_query_log
|
||||
-- disable_result_log
|
||||
-- enable_warnings
|
||||
|
||||
SET @old_innodb_stats_sample_pages=@@innodb_stats_sample_pages;
|
||||
SET GLOBAL innodb_stats_sample_pages=0;
|
||||
|
||||
# check that the value has been adjusted to 1
|
||||
-- enable_result_log
|
||||
SHOW VARIABLES LIKE 'innodb_stats_sample_pages';
|
||||
-- disable_result_log
|
||||
|
||||
CREATE TABLE innodb_analyze (
|
||||
a INT,
|
||||
b INT,
|
||||
KEY(a),
|
||||
KEY(b,a)
|
||||
) ENGINE=InnoDB;
|
||||
|
||||
# test with empty table
|
||||
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=2;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=4;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=8;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=16;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
INSERT INTO innodb_analyze VALUES
|
||||
(1,1), (1,1), (1,2), (1,3), (1,4), (1,5),
|
||||
(8,1), (8,8), (8,2), (7,1), (1,4), (3,5);
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=1;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=2;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=4;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=8;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
SET GLOBAL innodb_stats_sample_pages=16;
|
||||
ANALYZE TABLE innodb_analyze;
|
||||
|
||||
DROP TABLE innodb_analyze;
|
||||
SET GLOBAL innodb_stats_sample_pages=@old_innodb_stats_sample_pages;
|
||||
|
|
@ -396,7 +396,7 @@ DROP TABLE t1;
|
|||
#
|
||||
SET @@SESSION.AUTO_INCREMENT_INCREMENT=1, @@SESSION.AUTO_INCREMENT_OFFSET=1;
|
||||
SET @@INSERT_ID=1;
|
||||
SHOW VARIABLES LIKE "%auto_inc%";
|
||||
SHOW VARIABLES LIKE "auto_inc%";
|
||||
CREATE TABLE t1 (c1 DOUBLE NOT NULL AUTO_INCREMENT, c2 INT, PRIMARY KEY (c1)) ENGINE=InnoDB;
|
||||
INSERT INTO t1 VALUES(NULL, 1);
|
||||
INSERT INTO t1 VALUES(NULL, 2);
|
||||
|
|
|
|||
516
mysql-test/t/innodb-index.test
Normal file
516
mysql-test/t/innodb-index.test
Normal file
|
|
@ -0,0 +1,516 @@
|
|||
-- source include/have_innodb.inc
|
||||
|
||||
SET @save_innodb_file_format_check=@@global.innodb_file_format_check;
|
||||
|
||||
create table t1(a int not null, b int, c char(10) not null, d varchar(20)) engine = innodb;
|
||||
insert into t1 values (5,5,'oo','oo'),(4,4,'tr','tr'),(3,4,'ad','ad'),(2,3,'ak','ak');
|
||||
commit;
|
||||
--error ER_DUP_KEYNAME
|
||||
alter table t1 add index b (b), add index b (b);
|
||||
--error ER_DUP_FIELDNAME
|
||||
alter table t1 add index (b,b);
|
||||
alter table t1 add index d2 (d);
|
||||
show create table t1;
|
||||
explain select * from t1 force index(d2) order by d;
|
||||
select * from t1 force index (d2) order by d;
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique index (b);
|
||||
show create table t1;
|
||||
alter table t1 add index (b);
|
||||
show create table t1;
|
||||
|
||||
# Check how existing tables interfere with temporary tables.
|
||||
CREATE TABLE `t1#1`(a INT PRIMARY KEY) ENGINE=InnoDB;
|
||||
|
||||
call mtr.add_suppression(" table `test`\\.`t1#[12]` already exists in InnoDB internal");
|
||||
|
||||
--error 156
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
rename table `t1#1` to `t1#2`;
|
||||
--error 156
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
drop table `t1#2`;
|
||||
|
||||
alter table t1 add unique index (c), add index (d);
|
||||
show create table t1;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
alter table t1 add primary key (a), drop index c;
|
||||
show create table t1;
|
||||
--error ER_MULTIPLE_PRI_KEY
|
||||
alter table t1 add primary key (c);
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 drop primary key, add primary key (b);
|
||||
create unique index c on t1 (c);
|
||||
show create table t1;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
select * from t1 force index(c) order by c;
|
||||
alter table t1 drop index b, add index (b);
|
||||
show create table t1;
|
||||
insert into t1 values(6,1,'ggg','ggg');
|
||||
select * from t1;
|
||||
select * from t1 force index(b) order by b;
|
||||
select * from t1 force index(c) order by c;
|
||||
select * from t1 force index(d) order by d;
|
||||
explain select * from t1 force index(b) order by b;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
explain select * from t1 force index(d) order by d;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add index (c(2));
|
||||
show create table t1;
|
||||
alter table t1 add unique index (d(10));
|
||||
show create table t1;
|
||||
insert into t1 values(5,1,'ggg','ggg');
|
||||
select * from t1;
|
||||
select * from t1 force index(c) order by c;
|
||||
select * from t1 force index(d) order by d;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
explain select * from t1 force index(d) order by d;
|
||||
show create table t1;
|
||||
alter table t1 drop index d;
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
select * from t1 force index(c) order by c;
|
||||
explain select * from t1 order by b;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
explain select * from t1 order by d;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,2,'ad','ad'),(4,4,'afe','afe');
|
||||
commit;
|
||||
alter table t1 add unique index (b,c);
|
||||
insert into t1 values(8,9,'fff','fff');
|
||||
select * from t1;
|
||||
select * from t1 force index(b) order by b;
|
||||
explain select * from t1 force index(b) order by b;
|
||||
show create table t1;
|
||||
alter table t1 add index (b,c);
|
||||
insert into t1 values(11,11,'kkk','kkk');
|
||||
select * from t1;
|
||||
select * from t1 force index(b) order by b;
|
||||
explain select * from t1 force index(b) order by b;
|
||||
show create table t1;
|
||||
alter table t1 add unique index (c,d);
|
||||
insert into t1 values(13,13,'yyy','aaa');
|
||||
select * from t1;
|
||||
select * from t1 force index(b) order by b;
|
||||
select * from t1 force index(c) order by c;
|
||||
explain select * from t1 force index(b) order by b;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int not null, c int, primary key (a), key (b)) engine = innodb;
|
||||
create table t3(a int not null, c int not null, d int, primary key (a), key (c)) engine = innodb;
|
||||
create table t4(a int not null, d int not null, e int, primary key (a), key (d)) engine = innodb;
|
||||
create table t2(a int not null, b int not null, c int not null, d int not null, e int,
|
||||
foreign key (b) references t1(b) on delete cascade,
|
||||
foreign key (c) references t3(c), foreign key (d) references t4(d))
|
||||
engine = innodb;
|
||||
--error ER_DROP_INDEX_FK
|
||||
alter table t1 drop index b;
|
||||
--error ER_DROP_INDEX_FK
|
||||
alter table t3 drop index c;
|
||||
--error ER_DROP_INDEX_FK
|
||||
alter table t4 drop index d;
|
||||
--error ER_DROP_INDEX_FK
|
||||
alter table t2 drop index b;
|
||||
--error ER_DROP_INDEX_FK
|
||||
alter table t2 drop index b, drop index c, drop index d;
|
||||
# Apparently, the following makes mysql_alter_table() drop index d.
|
||||
create unique index dc on t2 (d,c);
|
||||
create index dc on t1 (b,c);
|
||||
# This should preserve the foreign key constraints.
|
||||
alter table t2 add primary key (a);
|
||||
insert into t1 values (1,1,1);
|
||||
insert into t3 values (1,1,1);
|
||||
insert into t4 values (1,1,1);
|
||||
insert into t2 values (1,1,1,1,1);
|
||||
commit;
|
||||
alter table t4 add constraint dc foreign key (a) references t1(a);
|
||||
show create table t4;
|
||||
--replace_regex /'test\.#sql-[0-9a-f_]*'/'#sql-temporary'/
|
||||
# a foreign key 'test/dc' already exists
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
alter table t3 add constraint dc foreign key (a) references t1(a);
|
||||
show create table t3;
|
||||
alter table t2 drop index b, add index (b);
|
||||
show create table t2;
|
||||
--error ER_ROW_IS_REFERENCED_2
|
||||
delete from t1;
|
||||
--error ER_CANT_DROP_FIELD_OR_KEY
|
||||
drop index dc on t4;
|
||||
# there is no foreign key dc on t3
|
||||
--replace_regex /'\.\/test\/#sql2-[0-9a-f-]*'/'#sql2-temporary'/
|
||||
--error ER_ERROR_ON_RENAME
|
||||
alter table t3 drop foreign key dc;
|
||||
alter table t4 drop foreign key dc;
|
||||
select * from t2;
|
||||
delete from t1;
|
||||
select * from t2;
|
||||
|
||||
drop table t2,t4,t3,t1;
|
||||
|
||||
-- let charset = utf8
|
||||
-- source include/innodb-index.inc
|
||||
|
||||
create table t1(a int not null, b int) engine = innodb;
|
||||
insert into t1 values (1,1),(1,1),(1,1),(1,1);
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique index (a);
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique index (b);
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique index (a), add unique index(b);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, c int not null,b int, primary key(a), unique key(c), key(b)) engine = innodb;
|
||||
alter table t1 drop index c, drop index b;
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, primary key(a)) engine = innodb;
|
||||
alter table t1 add index (b);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int, c char(10), d varchar(20), primary key (a)) engine = innodb;
|
||||
insert into t1 values (1,1,'ab','ab'),(2,2,'ac','ac'),(3,3,'ac','ac'),(4,4,'afe','afe'),(5,4,'affe','affe');
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique index (b), add unique index (c), add unique index (d);
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique index (c), add unique index (b), add index (d);
|
||||
show create table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int not null, c int, primary key (a), key(c)) engine=innodb;
|
||||
insert into t1 values (5,1,5),(4,2,4),(3,3,3),(2,4,2),(1,5,1);
|
||||
alter table t1 add unique index (b);
|
||||
insert into t1 values (10,20,20),(11,19,19),(12,18,18),(13,17,17);
|
||||
show create table t1;
|
||||
check table t1;
|
||||
explain select * from t1 force index(c) order by c;
|
||||
explain select * from t1 order by a;
|
||||
explain select * from t1 force index(b) order by b;
|
||||
select * from t1 order by a;
|
||||
select * from t1 force index(b) order by b;
|
||||
select * from t1 force index(c) order by c;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b int not null) engine=innodb;
|
||||
insert into t1 values (1,1);
|
||||
alter table t1 add primary key(b);
|
||||
insert into t1 values (2,2);
|
||||
show create table t1;
|
||||
check table t1;
|
||||
select * from t1;
|
||||
explain select * from t1;
|
||||
explain select * from t1 order by a;
|
||||
explain select * from t1 order by b;
|
||||
checksum table t1;
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null) engine=innodb;
|
||||
insert into t1 values (1);
|
||||
alter table t1 add primary key(a);
|
||||
insert into t1 values (2);
|
||||
show create table t1;
|
||||
check table t1;
|
||||
commit;
|
||||
select * from t1;
|
||||
explain select * from t1;
|
||||
explain select * from t1 order by a;
|
||||
drop table t1;
|
||||
|
||||
create table t2(d varchar(17) primary key) engine=innodb default charset=utf8;
|
||||
create table t3(a int primary key) engine=innodb;
|
||||
|
||||
insert into t3 values(22),(44),(33),(55),(66);
|
||||
|
||||
insert into t2 values ('jejdkrun87'),('adfd72nh9k'),
|
||||
('adfdpplkeock'),('adfdijnmnb78k'),('adfdijn0loKNHJik');
|
||||
|
||||
create table t1(a int, b blob, c text, d text not null)
|
||||
engine=innodb default charset = utf8;
|
||||
|
||||
# r2667 The following test is disabled because MySQL behavior changed.
|
||||
# r2667 The test was added with this comment:
|
||||
# r2667
|
||||
# r2667 ------------------------------------------------------------------------
|
||||
# r2667 r1699 | marko | 2007-08-10 19:53:19 +0300 (Fri, 10 Aug 2007) | 5 lines
|
||||
# r2667
|
||||
# r2667 branches/zip: Add changes that accidentally omitted from r1698:
|
||||
# r2667
|
||||
# r2667 innodb-index.test, innodb-index.result: Add a test for creating
|
||||
# r2667 a PRIMARY KEY on a column that contains a NULL value.
|
||||
# r2667 ------------------------------------------------------------------------
|
||||
# r2667
|
||||
# r2667 but in BZR-r2667:
|
||||
# r2667 http://bazaar.launchpad.net/~mysql/mysql-server/mysql-5.1/revision/davi%40mysql.com-20080617141221-8yre8ys9j4uw3xx5?start_revid=joerg%40mysql.com-20080630105418-7qoe5ehomgrcdb89
|
||||
# r2667 MySQL changed the behavior to do full table copy when creating PRIMARY INDEX
|
||||
# r2667 on a non-NULL column instead of calling ::add_index() which would fail (and
|
||||
# r2667 this is what we were testing here). Before r2667 the code execution path was
|
||||
# r2667 like this (when adding PRIMARY INDEX on a non-NULL column with ALTER TABLE):
|
||||
# r2667
|
||||
# r2667 mysql_alter_table()
|
||||
# r2667 compare_tables() // would return ALTER_TABLE_INDEX_CHANGED
|
||||
# r2667 ::add_index() // would fail with "primary index cannot contain NULL"
|
||||
# r2667
|
||||
# r2667 after r2667 the code execution path is the following:
|
||||
# r2667
|
||||
# r2667 mysql_alter_table()
|
||||
# r2667 compare_tables() // returns ALTER_TABLE_DATA_CHANGED
|
||||
# r2667 full copy is done, without calling ::add_index()
|
||||
# r2667
|
||||
# r2667 To enable, remove "# r2667: " below.
|
||||
# r2667
|
||||
# r2667: insert into t1 values (null,null,null,'null');
|
||||
insert into t1
|
||||
select a,left(repeat(d,100*a),65535),repeat(d,20*a),d from t2,t3;
|
||||
drop table t2, t3;
|
||||
select count(*) from t1 where a=44;
|
||||
select a,
|
||||
length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
|
||||
# r2667: --error ER_PRIMARY_CANT_HAVE_NULL
|
||||
# r2667: alter table t1 add primary key (a), add key (b(20));
|
||||
# r2667: delete from t1 where d='null';
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add primary key (a), add key (b(20));
|
||||
delete from t1 where a%2;
|
||||
check table t1;
|
||||
alter table t1 add primary key (a,b(255),c(255)), add key (b(767));
|
||||
select count(*) from t1 where a=44;
|
||||
select a,
|
||||
length(b),b=left(repeat(d,100*a),65535),length(c),c=repeat(d,20*a),d from t1;
|
||||
show create table t1;
|
||||
check table t1;
|
||||
explain select * from t1 where b like 'adfd%';
|
||||
|
||||
#
|
||||
# Test locking
|
||||
#
|
||||
|
||||
create table t2(a int, b varchar(255), primary key(a,b)) engine=innodb;
|
||||
insert into t2 select a,left(b,255) from t1;
|
||||
drop table t1;
|
||||
rename table t2 to t1;
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
connection a;
|
||||
set innodb_lock_wait_timeout=1;
|
||||
begin;
|
||||
# Obtain an IX lock on the table
|
||||
select a from t1 limit 1 for update;
|
||||
connection b;
|
||||
set innodb_lock_wait_timeout=1;
|
||||
# This would require an S lock on the table, conflicting with the IX lock.
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
create index t1ba on t1 (b,a);
|
||||
connection a;
|
||||
commit;
|
||||
begin;
|
||||
# Obtain an IS lock on the table
|
||||
select a from t1 limit 1 lock in share mode;
|
||||
connection b;
|
||||
# This will require an S lock on the table. No conflict with the IS lock.
|
||||
create index t1ba on t1 (b,a);
|
||||
# This would require an X lock on the table, conflicting with the IS lock.
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
drop index t1ba on t1;
|
||||
connection a;
|
||||
commit;
|
||||
explain select a from t1 order by b;
|
||||
--send
|
||||
select a,sleep(2+a/100) from t1 order by b limit 3;
|
||||
|
||||
# The following DROP INDEX will succeed, altough the SELECT above has
|
||||
# opened a read view. However, during the execution of the SELECT,
|
||||
# MySQL should hold a table lock that should block the execution
|
||||
# of the DROP INDEX below.
|
||||
|
||||
connection b;
|
||||
select sleep(1);
|
||||
drop index t1ba on t1;
|
||||
|
||||
# After the index was dropped, subsequent SELECTs will use the same
|
||||
# read view, but they should not be accessing the dropped index any more.
|
||||
|
||||
connection a;
|
||||
reap;
|
||||
explain select a from t1 order by b;
|
||||
select a from t1 order by b limit 3;
|
||||
commit;
|
||||
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
|
||||
drop table t1;
|
||||
|
||||
let $per_table=`select @@innodb_file_per_table`;
|
||||
let $format=`select @@innodb_file_format`;
|
||||
set global innodb_file_per_table=on;
|
||||
set global innodb_file_format='Barracuda';
|
||||
# Test creating a table that could lead to undo log overflow.
|
||||
# In the undo log, we write a 768-byte prefix (REC_MAX_INDEX_COL_LEN)
|
||||
# of each externally stored column that appears as a column prefix in an index.
|
||||
# For this test case, it would suffice to write 1 byte, though.
|
||||
create table t1(a blob,b blob,c blob,d blob,e blob,f blob,g blob,h blob,
|
||||
i blob,j blob,k blob,l blob,m blob,n blob,o blob,p blob,
|
||||
q blob,r blob,s blob,t blob,u blob)
|
||||
engine=innodb row_format=dynamic;
|
||||
create index t1a on t1 (a(1));
|
||||
create index t1b on t1 (b(1));
|
||||
create index t1c on t1 (c(1));
|
||||
create index t1d on t1 (d(1));
|
||||
create index t1e on t1 (e(1));
|
||||
create index t1f on t1 (f(1));
|
||||
create index t1g on t1 (g(1));
|
||||
create index t1h on t1 (h(1));
|
||||
create index t1i on t1 (i(1));
|
||||
create index t1j on t1 (j(1));
|
||||
create index t1k on t1 (k(1));
|
||||
create index t1l on t1 (l(1));
|
||||
create index t1m on t1 (m(1));
|
||||
create index t1n on t1 (n(1));
|
||||
create index t1o on t1 (o(1));
|
||||
create index t1p on t1 (p(1));
|
||||
create index t1q on t1 (q(1));
|
||||
create index t1r on t1 (r(1));
|
||||
create index t1s on t1 (s(1));
|
||||
create index t1t on t1 (t(1));
|
||||
--error 139
|
||||
create index t1u on t1 (u(1));
|
||||
--error 139
|
||||
create index t1ut on t1 (u(1), t(1));
|
||||
create index t1st on t1 (s(1), t(1));
|
||||
show create table t1;
|
||||
--error 139
|
||||
create index t1u on t1 (u(1));
|
||||
alter table t1 row_format=compact;
|
||||
create index t1u on t1 (u(1));
|
||||
|
||||
drop table t1;
|
||||
eval set global innodb_file_per_table=$per_table;
|
||||
eval set global innodb_file_format=$format;
|
||||
|
||||
#
|
||||
# Test to check whether CREATE INDEX handles implicit foreign key
|
||||
# constraint modifications (Issue #70, Bug #38786)
|
||||
#
|
||||
SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0;
|
||||
SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0;
|
||||
|
||||
CREATE TABLE t1(
|
||||
c1 BIGINT(12) NOT NULL,
|
||||
PRIMARY KEY (c1)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
CREATE TABLE t2(
|
||||
c1 BIGINT(16) NOT NULL,
|
||||
c2 BIGINT(12) NOT NULL,
|
||||
c3 BIGINT(12) NOT NULL,
|
||||
PRIMARY KEY (c1)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
|
||||
FOREIGN KEY (c3) REFERENCES t1(c1);
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
|
||||
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
|
||||
|
||||
SHOW CREATE TABLE t2;
|
||||
|
||||
CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
|
||||
|
||||
SHOW CREATE TABLE t2;
|
||||
|
||||
SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS;
|
||||
SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS;
|
||||
|
||||
--error ER_NO_REFERENCED_ROW_2
|
||||
INSERT INTO t2 VALUES(0,0,0);
|
||||
INSERT INTO t1 VALUES(0);
|
||||
INSERT INTO t2 VALUES(0,0,0);
|
||||
|
||||
DROP TABLE t2;
|
||||
|
||||
CREATE TABLE t2(
|
||||
c1 BIGINT(16) NOT NULL,
|
||||
c2 BIGINT(12) NOT NULL,
|
||||
c3 BIGINT(12) NOT NULL,
|
||||
PRIMARY KEY (c1,c2,c3)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
|
||||
FOREIGN KEY (c3) REFERENCES t1(c1);
|
||||
|
||||
SHOW CREATE TABLE t2;
|
||||
|
||||
CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
|
||||
|
||||
SHOW CREATE TABLE t2;
|
||||
--error ER_NO_REFERENCED_ROW_2
|
||||
INSERT INTO t2 VALUES(0,0,1);
|
||||
INSERT INTO t2 VALUES(0,0,0);
|
||||
--error ER_ROW_IS_REFERENCED_2
|
||||
DELETE FROM t1;
|
||||
DELETE FROM t2;
|
||||
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
||||
|
||||
CREATE TABLE t1(
|
||||
c1 BIGINT(12) NOT NULL,
|
||||
c2 INT(4) NOT NULL,
|
||||
PRIMARY KEY (c2,c1)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
CREATE TABLE t2(
|
||||
c1 BIGINT(16) NOT NULL,
|
||||
c2 BIGINT(12) NOT NULL,
|
||||
c3 BIGINT(12) NOT NULL,
|
||||
PRIMARY KEY (c1)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
|
||||
|
||||
--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
|
||||
FOREIGN KEY (c3,c2) REFERENCES t1(c1,c1);
|
||||
--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
|
||||
FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2);
|
||||
--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
|
||||
FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1);
|
||||
ALTER TABLE t1 MODIFY COLUMN c2 BIGINT(12) NOT NULL;
|
||||
--replace_regex /'test\.#sql-[0-9_a-f-]*'/'#sql-temporary'/
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
|
||||
FOREIGN KEY (c3,c2) REFERENCES t1(c1,c2);
|
||||
|
||||
ALTER TABLE t2 ADD CONSTRAINT fk_t2_ca
|
||||
FOREIGN KEY (c3,c2) REFERENCES t1(c2,c1);
|
||||
SHOW CREATE TABLE t1;
|
||||
SHOW CREATE TABLE t2;
|
||||
CREATE INDEX i_t2_c2_c1 ON t2(c2, c1);
|
||||
SHOW CREATE TABLE t2;
|
||||
CREATE INDEX i_t2_c3_c1_c2 ON t2(c3, c1, c2);
|
||||
SHOW CREATE TABLE t2;
|
||||
CREATE INDEX i_t2_c3_c2 ON t2(c3, c2);
|
||||
SHOW CREATE TABLE t2;
|
||||
|
||||
DROP TABLE t2;
|
||||
DROP TABLE t1;
|
||||
SET GLOBAL innodb_file_format_check=@save_innodb_file_format_check;
|
||||
5
mysql-test/t/innodb-index_ucs2.test
Normal file
5
mysql-test/t/innodb-index_ucs2.test
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
-- source include/have_innodb.inc
|
||||
-- source include/have_ucs2.inc
|
||||
|
||||
-- let charset = ucs2
|
||||
-- source include/innodb-index.inc
|
||||
64
mysql-test/t/innodb-timeout.test
Normal file
64
mysql-test/t/innodb-timeout.test
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
-- source include/have_innodb.inc
|
||||
|
||||
let $timeout=`select @@innodb_lock_wait_timeout`;
|
||||
set global innodb_lock_wait_timeout=42;
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
|
||||
connection a;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
set innodb_lock_wait_timeout=1;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
|
||||
connection b;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
set global innodb_lock_wait_timeout=347;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
set innodb_lock_wait_timeout=1;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
|
||||
connect (c,localhost,root,,);
|
||||
connection c;
|
||||
select @@innodb_lock_wait_timeout;
|
||||
connection default;
|
||||
disconnect c;
|
||||
|
||||
connection a;
|
||||
create table t1(a int primary key)engine=innodb;
|
||||
begin;
|
||||
insert into t1 values(1),(2),(3);
|
||||
|
||||
connection b;
|
||||
--send
|
||||
select * from t1 for update;
|
||||
|
||||
connection a;
|
||||
commit;
|
||||
|
||||
connection b;
|
||||
reap;
|
||||
|
||||
connection a;
|
||||
begin;
|
||||
insert into t1 values(4);
|
||||
|
||||
connection b;
|
||||
--send
|
||||
select * from t1 for update;
|
||||
|
||||
connection a;
|
||||
sleep 2;
|
||||
commit;
|
||||
|
||||
connection b;
|
||||
--error ER_LOCK_WAIT_TIMEOUT
|
||||
reap;
|
||||
drop table t1;
|
||||
|
||||
connection default;
|
||||
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
|
||||
eval set global innodb_lock_wait_timeout=$timeout;
|
||||
2
mysql-test/t/innodb-use-sys-malloc-master.opt
Normal file
2
mysql-test/t/innodb-use-sys-malloc-master.opt
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
--innodb-use-sys-malloc=true
|
||||
--innodb-use-sys-malloc=true
|
||||
51
mysql-test/t/innodb-use-sys-malloc.test
Normal file
51
mysql-test/t/innodb-use-sys-malloc.test
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
--source include/have_innodb.inc
|
||||
# XtraDB has lots of memory leak warnings at shutdown when
|
||||
# --innodb-use-sys-malloc
|
||||
--source include/not_valgrind.inc
|
||||
|
||||
#display current value of innodb_use_sys_malloc
|
||||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
--echo 1 Expected
|
||||
|
||||
#try changing it. Should fail.
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
SET @@GLOBAL.innodb_use_sys_malloc=0;
|
||||
--echo Expected error 'Read only variable'
|
||||
|
||||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
--echo 1 Expected
|
||||
|
||||
|
||||
#do some stuff to see if it works.
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
|
||||
create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
|
||||
insert into t1 values (1),(2),(3),(4),(5),(6),(7);
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
--source include/have_innodb.inc
|
||||
|
||||
#display current value of innodb_use_sys_malloc
|
||||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
--echo 1 Expected
|
||||
|
||||
#try changing it. Should fail.
|
||||
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
|
||||
SET @@GLOBAL.innodb_use_sys_malloc=0;
|
||||
--echo Expected error 'Read only variable'
|
||||
|
||||
SELECT @@GLOBAL.innodb_use_sys_malloc;
|
||||
--echo 1 Expected
|
||||
|
||||
|
||||
#do some stuff to see if it works.
|
||||
--disable_warnings
|
||||
drop table if exists t1;
|
||||
--enable_warnings
|
||||
|
||||
create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
|
||||
insert into t1 values (1),(2),(3),(4),(5),(6),(7);
|
||||
select * from t1;
|
||||
drop table t1;
|
||||
347
mysql-test/t/innodb-zip.test
Normal file
347
mysql-test/t/innodb-zip.test
Normal file
|
|
@ -0,0 +1,347 @@
|
|||
-- source include/have_innodb.inc
|
||||
|
||||
let $per_table=`select @@innodb_file_per_table`;
|
||||
let $format=`select @@innodb_file_format`;
|
||||
let $innodb_file_format_check_orig=`select @@innodb_file_format_check`;
|
||||
set global innodb_file_per_table=off;
|
||||
set global innodb_file_format=`0`;
|
||||
|
||||
create table t0(a int primary key) engine=innodb row_format=compressed;
|
||||
create table t00(a int primary key) engine=innodb
|
||||
key_block_size=4 row_format=compressed;
|
||||
create table t1(a int primary key) engine=innodb row_format=dynamic;
|
||||
create table t2(a int primary key) engine=innodb row_format=redundant;
|
||||
create table t3(a int primary key) engine=innodb row_format=compact;
|
||||
create table t4(a int primary key) engine=innodb key_block_size=9;
|
||||
create table t5(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=redundant;
|
||||
|
||||
set global innodb_file_per_table=on;
|
||||
create table t6(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=redundant;
|
||||
set global innodb_file_format=`1`;
|
||||
create table t7(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=redundant;
|
||||
create table t8(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=fixed;
|
||||
create table t9(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=compact;
|
||||
create table t10(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=dynamic;
|
||||
create table t11(a int primary key) engine=innodb
|
||||
key_block_size=1 row_format=compressed;
|
||||
create table t12(a int primary key) engine=innodb
|
||||
key_block_size=1;
|
||||
create table t13(a int primary key) engine=innodb
|
||||
row_format=compressed;
|
||||
create table t14(a int primary key) engine=innodb key_block_size=9;
|
||||
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
|
||||
drop table t0,t00,t2,t3,t4,t5,t6,t7,t8,t9,t10,t11,t12,t13,t14;
|
||||
alter table t1 key_block_size=0;
|
||||
alter table t1 row_format=dynamic;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
alter table t1 row_format=compact;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
alter table t1 row_format=redundant;
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
drop table t1;
|
||||
|
||||
create table t1(a int not null, b text, index(b(10))) engine=innodb
|
||||
key_block_size=1;
|
||||
|
||||
create table t2(b text)engine=innodb;
|
||||
insert into t2 values(concat('1abcdefghijklmnopqrstuvwxyz', repeat('A',5000)));
|
||||
|
||||
insert into t1 select 1, b from t2;
|
||||
commit;
|
||||
|
||||
connect (a,localhost,root,,);
|
||||
connect (b,localhost,root,,);
|
||||
|
||||
connection a;
|
||||
begin;
|
||||
update t1 set b=repeat('B',100);
|
||||
|
||||
connection b;
|
||||
select a,left(b,40) from t1 natural join t2;
|
||||
|
||||
connection a;
|
||||
rollback;
|
||||
|
||||
connection b;
|
||||
select a,left(b,40) from t1 natural join t2;
|
||||
|
||||
connection default;
|
||||
disconnect a;
|
||||
disconnect b;
|
||||
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
drop table t1,t2;
|
||||
|
||||
# The following should fail even in non-strict mode.
|
||||
SET SESSION innodb_strict_mode = off;
|
||||
--error ER_TOO_BIG_ROWSIZE
|
||||
CREATE TABLE t1(
|
||||
c TEXT NOT NULL, d TEXT NOT NULL,
|
||||
PRIMARY KEY (c(767),d(767)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
|
||||
--error ER_TOO_BIG_ROWSIZE
|
||||
CREATE TABLE t1(
|
||||
c TEXT NOT NULL, d TEXT NOT NULL,
|
||||
PRIMARY KEY (c(767),d(767)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2 CHARSET=ASCII;
|
||||
CREATE TABLE t1(
|
||||
c TEXT NOT NULL, d TEXT NOT NULL,
|
||||
PRIMARY KEY (c(767),d(767)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4 CHARSET=ASCII;
|
||||
drop table t1;
|
||||
--error ER_TOO_BIG_ROWSIZE
|
||||
CREATE TABLE t1(c TEXT, PRIMARY KEY (c(440)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
|
||||
# The maximum key size for a compressed row actually depends on the
|
||||
# version of libz used, as account must be taken for the maximum
|
||||
# compressed size of a key, and this differs between libz
|
||||
# versions. Some libz versions allow a size of 439, some only 438.
|
||||
CREATE TABLE t1(c TEXT, PRIMARY KEY (c(438)))
|
||||
ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=1 CHARSET=ASCII;
|
||||
INSERT INTO t1 VALUES(REPEAT('A',512)),(REPEAT('B',512));
|
||||
DROP TABLE t1;
|
||||
|
||||
#
|
||||
# Test blob column inheritance (mantis issue#36)
|
||||
#
|
||||
|
||||
create table t1( c1 int not null, c2 blob, c3 blob, c4 blob,
|
||||
primary key(c1, c2(22), c3(22)))
|
||||
engine = innodb row_format = dynamic;
|
||||
begin;
|
||||
insert into t1 values(1, repeat('A', 20000), repeat('B', 20000),
|
||||
repeat('C', 20000));
|
||||
|
||||
update t1 set c3 = repeat('D', 20000) where c1 = 1;
|
||||
commit;
|
||||
|
||||
# one blob column which is unchanged in update and part of PK
|
||||
# one blob column which is changed and part of of PK
|
||||
# one blob column which is not part of PK and is unchanged
|
||||
select count(*) from t1 where c2 = repeat('A', 20000);
|
||||
select count(*) from t1 where c3 = repeat('D', 20000);
|
||||
select count(*) from t1 where c4 = repeat('C', 20000);
|
||||
|
||||
update t1 set c3 = repeat('E', 20000) where c1 = 1;
|
||||
drop table t1;
|
||||
|
||||
#
|
||||
#
|
||||
# Test innodb_file_format
|
||||
#
|
||||
set global innodb_file_format=`0`;
|
||||
select @@innodb_file_format;
|
||||
set global innodb_file_format=`1`;
|
||||
select @@innodb_file_format;
|
||||
-- error ER_WRONG_ARGUMENTS
|
||||
set global innodb_file_format=`2`;
|
||||
-- error ER_WRONG_ARGUMENTS
|
||||
set global innodb_file_format=`-1`;
|
||||
set global innodb_file_format=`Antelope`;
|
||||
set global innodb_file_format=`Barracuda`;
|
||||
-- error ER_WRONG_ARGUMENTS
|
||||
set global innodb_file_format=`Cheetah`;
|
||||
-- error ER_WRONG_ARGUMENTS
|
||||
set global innodb_file_format=`abc`;
|
||||
-- error ER_WRONG_ARGUMENTS
|
||||
set global innodb_file_format=`1a`;
|
||||
-- error ER_WRONG_ARGUMENTS
|
||||
set global innodb_file_format=``;
|
||||
|
||||
#test strict mode.
|
||||
# this does not work anymore, has been removed from mysqltest
|
||||
# -- enable_errors
|
||||
set global innodb_file_per_table = on;
|
||||
set global innodb_file_format = `1`;
|
||||
|
||||
set innodb_strict_mode = off;
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 0;
|
||||
drop table t1;
|
||||
|
||||
#set strict_mode
|
||||
set innodb_strict_mode = on;
|
||||
|
||||
#Test different values of KEY_BLOCK_SIZE
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 0;
|
||||
show errors;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t2 (id int primary key) engine = innodb key_block_size = 9;
|
||||
show errors;
|
||||
|
||||
|
||||
create table t3 (id int primary key) engine = innodb key_block_size = 1;
|
||||
create table t4 (id int primary key) engine = innodb key_block_size = 2;
|
||||
create table t5 (id int primary key) engine = innodb key_block_size = 4;
|
||||
create table t6 (id int primary key) engine = innodb key_block_size = 8;
|
||||
create table t7 (id int primary key) engine = innodb key_block_size = 16;
|
||||
|
||||
#check various ROW_FORMAT values.
|
||||
create table t8 (id int primary key) engine = innodb row_format = compressed;
|
||||
create table t9 (id int primary key) engine = innodb row_format = dynamic;
|
||||
create table t10(id int primary key) engine = innodb row_format = compact;
|
||||
create table t11(id int primary key) engine = innodb row_format = redundant;
|
||||
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
drop table t3, t4, t5, t6, t7, t8, t9, t10, t11;
|
||||
|
||||
#test different values of ROW_FORMAT with KEY_BLOCK_SIZE
|
||||
create table t1 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = compressed;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t2 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = redundant;
|
||||
show errors;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t3 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = compact;
|
||||
show errors;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t4 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = dynamic;
|
||||
show errors;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t5 (id int primary key) engine = innodb
|
||||
key_block_size = 8 row_format = default;
|
||||
show errors;
|
||||
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
drop table t1;
|
||||
|
||||
#test multiple errors
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t1 (id int primary key) engine = innodb
|
||||
key_block_size = 9 row_format = redundant;
|
||||
show errors;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t2 (id int primary key) engine = innodb
|
||||
key_block_size = 9 row_format = compact;
|
||||
show errors;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t2 (id int primary key) engine = innodb
|
||||
key_block_size = 9 row_format = dynamic;
|
||||
show errors;
|
||||
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
|
||||
#test valid values with innodb_file_per_table unset
|
||||
set global innodb_file_per_table = off;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 1;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t2 (id int primary key) engine = innodb key_block_size = 2;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t3 (id int primary key) engine = innodb key_block_size = 4;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t4 (id int primary key) engine = innodb key_block_size = 8;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t5 (id int primary key) engine = innodb key_block_size = 16;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t6 (id int primary key) engine = innodb row_format = compressed;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t7 (id int primary key) engine = innodb row_format = dynamic;
|
||||
show errors;
|
||||
create table t8 (id int primary key) engine = innodb row_format = compact;
|
||||
create table t9 (id int primary key) engine = innodb row_format = redundant;
|
||||
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
drop table t8, t9;
|
||||
|
||||
#test valid values with innodb_file_format unset
|
||||
set global innodb_file_per_table = on;
|
||||
set global innodb_file_format = `0`;
|
||||
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t1 (id int primary key) engine = innodb key_block_size = 1;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t2 (id int primary key) engine = innodb key_block_size = 2;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t3 (id int primary key) engine = innodb key_block_size = 4;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t4 (id int primary key) engine = innodb key_block_size = 8;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t5 (id int primary key) engine = innodb key_block_size = 16;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t6 (id int primary key) engine = innodb row_format = compressed;
|
||||
show errors;
|
||||
--error ER_CANT_CREATE_TABLE
|
||||
create table t7 (id int primary key) engine = innodb row_format = dynamic;
|
||||
show errors;
|
||||
create table t8 (id int primary key) engine = innodb row_format = compact;
|
||||
create table t9 (id int primary key) engine = innodb row_format = redundant;
|
||||
|
||||
SELECT table_schema, table_name, row_format
|
||||
FROM information_schema.tables WHERE engine='innodb';
|
||||
drop table t8, t9;
|
||||
|
||||
eval set global innodb_file_per_table=$per_table;
|
||||
eval set global innodb_file_format=$format;
|
||||
#
|
||||
# Testing of tablespace tagging
|
||||
#
|
||||
-- disable_info
|
||||
set global innodb_file_per_table=on;
|
||||
set global innodb_file_format=`Barracuda`;
|
||||
set global innodb_file_format_check=`Antelope`;
|
||||
create table normal_table (
|
||||
c1 int
|
||||
) engine = innodb;
|
||||
select @@innodb_file_format_check;
|
||||
create table zip_table (
|
||||
c1 int
|
||||
) engine = innodb key_block_size = 8;
|
||||
select @@innodb_file_format_check;
|
||||
set global innodb_file_format_check=`Antelope`;
|
||||
select @@innodb_file_format_check;
|
||||
-- disable_result_log
|
||||
show table status;
|
||||
-- enable_result_log
|
||||
select @@innodb_file_format_check;
|
||||
drop table normal_table, zip_table;
|
||||
-- disable_result_log
|
||||
|
||||
#
|
||||
# restore environment to the state it was before this test execution
|
||||
#
|
||||
|
||||
-- disable_query_log
|
||||
eval set global innodb_file_format=$format;
|
||||
eval set global innodb_file_per_table=$per_table;
|
||||
eval set global innodb_file_format_check=$innodb_file_format_check_orig;
|
||||
|
|
@ -1126,7 +1126,7 @@ show create table t2;
|
|||
create index id2 on t2 (id);
|
||||
show create table t2;
|
||||
drop index id2 on t2;
|
||||
--error 1025,1025
|
||||
--error ER_DROP_INDEX_FK
|
||||
drop index id on t2;
|
||||
show create table t2;
|
||||
drop table t2;
|
||||
|
|
@ -1294,6 +1294,7 @@ drop table t1;
|
|||
|
||||
# Test for testable InnoDB status variables. This test
|
||||
# uses previous ones(pages_created, rows_deleted, ...).
|
||||
--replace_result 512 511
|
||||
show status like "Innodb_buffer_pool_pages_total";
|
||||
show status like "Innodb_page_size";
|
||||
show status like "Innodb_rows_deleted";
|
||||
|
|
@ -2357,6 +2358,7 @@ DROP TABLE t1,t2;
|
|||
#
|
||||
# Bug #21101 (Prints wrong error message if max row size is too large)
|
||||
#
|
||||
set innodb_strict_mode=on;
|
||||
--error 1118
|
||||
CREATE TABLE t1 (
|
||||
c01 CHAR(255), c02 CHAR(255), c03 CHAR(255), c04 CHAR(255),
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@
|
|||
-- disable_result_log
|
||||
|
||||
# set packet size and reconnect
|
||||
SET @save_max_allowed_packet=@@global.max_allowed_packet;
|
||||
SET @@global.max_allowed_packet=16777216;
|
||||
--connect (newconn, localhost, root,,)
|
||||
|
||||
|
|
@ -21,7 +22,6 @@ CREATE TABLE bug34300 (
|
|||
|
||||
INSERT INTO bug34300 VALUES ('xxx', repeat('a', 8459264), 'zzz');
|
||||
|
||||
-- enable_query_log
|
||||
-- enable_result_log
|
||||
|
||||
SELECT f4, f8 FROM bug34300;
|
||||
|
|
@ -31,11 +31,6 @@ ALTER TABLE bug34300 ADD COLUMN (f10 INT);
|
|||
SELECT f4, f8 FROM bug34300;
|
||||
|
||||
DROP TABLE bug34300;
|
||||
|
||||
disconnect newconn;
|
||||
connection default;
|
||||
--disable_result_log
|
||||
--disable_query_log
|
||||
SET @@global.max_allowed_packet=default;
|
||||
--enable_result_log
|
||||
--enable_query_log
|
||||
SET @@global.max_allowed_packet=@save_max_allowed_packet;
|
||||
|
|
|
|||
1162
mysql-test/t/innodb_bug36169.test
Normal file
1162
mysql-test/t/innodb_bug36169.test
Normal file
File diff suppressed because it is too large
Load diff
34
mysql-test/t/innodb_bug36172.test
Normal file
34
mysql-test/t/innodb_bug36172.test
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
#
|
||||
# Test case for bug 36172
|
||||
#
|
||||
|
||||
-- source include/not_embedded.inc
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
SET storage_engine=InnoDB;
|
||||
|
||||
# we do not really care about what gets printed, we are only
|
||||
# interested in getting success or failure according to our
|
||||
# expectations
|
||||
|
||||
-- disable_query_log
|
||||
-- disable_result_log
|
||||
set @old_innodb_file_per_table=@@innodb_file_per_table;
|
||||
set @old_innodb_file_format=@@innodb_file_format;
|
||||
set @old_innodb_file_format_check=@@innodb_file_format_check;
|
||||
|
||||
SET GLOBAL innodb_file_format='Barracuda';
|
||||
SET GLOBAL innodb_file_per_table=on;
|
||||
|
||||
DROP TABLE IF EXISTS `table0`;
|
||||
CREATE TABLE `table0` ( `col0` tinyint(1) DEFAULT NULL, `col1` tinyint(1) DEFAULT NULL, `col2` tinyint(4) DEFAULT NULL, `col3` date DEFAULT NULL, `col4` time DEFAULT NULL, `col5` set('test1','test2','test3') DEFAULT NULL, `col6` time DEFAULT NULL, `col7` text, `col8` decimal(10,0) DEFAULT NULL, `col9` set('test1','test2','test3') DEFAULT NULL, `col10` float DEFAULT NULL, `col11` double DEFAULT NULL, `col12` enum('test1','test2','test3') DEFAULT NULL, `col13` tinyblob, `col14` year(4) DEFAULT NULL, `col15` set('test1','test2','test3') DEFAULT NULL, `col16` decimal(10,0) DEFAULT NULL, `col17` decimal(10,0) DEFAULT NULL, `col18` blob, `col19` datetime DEFAULT NULL, `col20` double DEFAULT NULL, `col21` decimal(10,0) DEFAULT NULL, `col22` datetime DEFAULT NULL, `col23` decimal(10,0) DEFAULT NULL, `col24` decimal(10,0) DEFAULT NULL, `col25` longtext, `col26` tinyblob, `col27` time DEFAULT NULL, `col28` tinyblob, `col29` enum('test1','test2','test3') DEFAULT NULL, `col30` smallint(6) DEFAULT NULL, `col31` double DEFAULT NULL, `col32` float DEFAULT NULL, `col33` char(175) DEFAULT NULL, `col34` tinytext, `col35` tinytext, `col36` tinyblob, `col37` tinyblob, `col38` tinytext, `col39` mediumblob, `col40` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, `col41` double DEFAULT NULL, `col42` smallint(6) DEFAULT NULL, `col43` longblob, `col44` varchar(80) DEFAULT NULL, `col45` mediumtext, `col46` decimal(10,0) DEFAULT NULL, `col47` bigint(20) DEFAULT NULL, `col48` date DEFAULT NULL, `col49` tinyblob, `col50` date DEFAULT NULL, `col51` tinyint(1) DEFAULT NULL, `col52` mediumint(9) DEFAULT NULL, `col53` float DEFAULT NULL, `col54` tinyblob, `col55` longtext, `col56` smallint(6) DEFAULT NULL, `col57` enum('test1','test2','test3') DEFAULT NULL, `col58` datetime DEFAULT NULL, `col59` mediumtext, `col60` varchar(232) DEFAULT NULL, `col61` decimal(10,0) DEFAULT NULL, `col62` year(4) DEFAULT NULL, `col63` smallint(6) DEFAULT NULL, `col64` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col65` blob, `col66` longblob, `col67` int(11) DEFAULT NULL, `col68` longtext, `col69` enum('test1','test2','test3') DEFAULT NULL, `col70` int(11) DEFAULT NULL, `col71` time DEFAULT NULL, `col72` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col73` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', `col74` varchar(170) DEFAULT NULL, `col75` set('test1','test2','test3') DEFAULT NULL, `col76` tinyblob, `col77` bigint(20) DEFAULT NULL, `col78` decimal(10,0) DEFAULT NULL, `col79` datetime DEFAULT NULL, `col80` year(4) DEFAULT NULL, `col81` decimal(10,0) DEFAULT NULL, `col82` longblob, `col83` text, `col84` char(83) DEFAULT NULL, `col85` decimal(10,0) DEFAULT NULL, `col86` float DEFAULT NULL, `col87` int(11) DEFAULT NULL, `col88` varchar(145) DEFAULT NULL, `col89` date DEFAULT NULL, `col90` decimal(10,0) DEFAULT NULL, `col91` decimal(10,0) DEFAULT NULL, `col92` mediumblob, `col93` time DEFAULT NULL, KEY `idx0` (`col69`,`col90`,`col8`), KEY `idx1` (`col60`), KEY `idx2` (`col60`,`col70`,`col74`), KEY `idx3` (`col22`,`col32`,`col72`,`col30`), KEY `idx4` (`col29`), KEY `idx5` (`col19`,`col45`(143)), KEY `idx6` (`col46`,`col48`,`col5`,`col39`(118)), KEY `idx7` (`col48`,`col61`), KEY `idx8` (`col93`), KEY `idx9` (`col31`), KEY `idx10` (`col30`,`col21`), KEY `idx11` (`col67`), KEY `idx12` (`col44`,`col6`,`col8`,`col38`(226)), KEY `idx13` (`col71`,`col41`,`col15`,`col49`(88)), KEY `idx14` (`col78`), KEY `idx15` (`col63`,`col67`,`col64`), KEY `idx16` (`col17`,`col86`), KEY `idx17` (`col77`,`col56`,`col10`,`col55`(24)), KEY `idx18` (`col62`), KEY `idx19` (`col31`,`col57`,`col56`,`col53`), KEY `idx20` (`col46`), KEY `idx21` (`col83`(54)), KEY `idx22` (`col51`,`col7`(120)), KEY `idx23` (`col7`(163),`col31`,`col71`,`col14`) ) ENGINE=InnoDB DEFAULT CHARSET=latin1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=2;
|
||||
insert ignore into `table0` set `col23` = 7887371.5084383683, `col24` = 4293854615.6906948000, `col25` = 'vitalist', `col26` = 'widespread', `col27` = '3570490', `col28` = 'habitual', `col30` = -5471, `col31` = 4286985783.6771750000, `col32` = 6354540.9826654866, `col33` = 'defoliation', `col34` = 'logarithms', `col35` = 'tegument\'s', `col36` = 'scouting\'s', `col37` = 'intermittency', `col38` = 'elongates', `col39` = 'prophecies', `col40` = '20560103035939', `col41` = 4292809130.0544143000, `col42` = 22057, `col43` = 'Hess\'s', `col44` = 'bandstand', `col45` = 'phenylketonuria', `col46` = 6338767.4018677324, `col47` = 5310247, `col48` = '12592418', `col49` = 'churchman\'s', `col50` = '32226125', `col51` = -58, `col52` = -6207968, `col53` = 1244839.3255104220, `col54` = 'robotized', `col55` = 'monotonous', `col56` = -26909, `col58` = '20720107023550', `col59` = 'suggestiveness\'s', `col60` = 'gemology', `col61` = 4287800670.2229986000, `col62` = '1944', `col63` = -16827, `col64` = '20700107212324', `col65` = 'Nicolais', `col66` = 'apteryx', `col67` = 6935317, `col68` = 'stroganoff', `col70` = 3316430, `col71` = '3277608', `col72` = '19300511045918', `col73` = '20421201003327', `col74` = 'attenuant', `col75` = '15173', `col76` = 'upstroke\'s', `col77` = 8118987, `col78` = 6791516.2735374002, `col79` = '20780701144624', `col80` = '2134', `col81` = 4290682351.3127537000, `col82` = 'unexplainably', `col83` = 'Storm', `col84` = 'Greyso\'s', `col85` = 4289119212.4306774000, `col86` = 7617575.8796655172, `col87` = -6325335, `col88` = 'fondue\'s', `col89` = '40608940', `col90` = 1659421.8093508712, `col91` = 8346904.6584368423, `col92` = 'reloads', `col93` = '5188366';
|
||||
CHECK TABLE table0 EXTENDED;
|
||||
INSERT IGNORE INTO `table0` SET `col19` = '19940127002709', `col20` = 2383927.9055146948, `col21` = 4293243420.5621204000, `col22` = '20511211123705', `col23` = 4289899778.6573381000, `col24` = 4293449279.0540481000, `col25` = 'emphysemic', `col26` = 'dentally', `col27` = '2347406', `col28` = 'eruct', `col30` = 1222, `col31` = 4294372994.9941406000, `col32` = 4291385574.1173744000, `col33` = 'borrowing\'s', `col34` = 'septics', `col35` = 'ratter\'s', `col36` = 'Kaye', `col37` = 'Florentia', `col38` = 'allium', `col39` = 'barkeep', `col40` = '19510407003441', `col41` = 4293559200.4215522000, `col42` = 22482, `col43` = 'decussate', `col44` = 'Brom\'s', `col45` = 'violated', `col46` = 4925506.4635456400, `col47` = 930549, `col48` = '51296066', `col49` = 'voluminously', `col50` = '29306676', `col51` = -88, `col52` = -2153690, `col53` = 4290250202.1464887000, `col54` = 'expropriation', `col55` = 'Aberdeen\'s', `col56` = 20343, `col58` = '19640415171532', `col59` = 'extern', `col60` = 'Ubana', `col61` = 4290487961.8539081000, `col62` = '2147', `col63` = -24271, `col64` = '20750801194548', `col65` = 'Cunaxa\'s', `col66` = 'pasticcio', `col67` = 2795817, `col68` = 'Indore\'s', `col70` = 6864127, `col71` = '1817832', `col72` = '20540506114211', `col73` = '20040101012300', `col74` = 'rationalized', `col75` = '45522', `col76` = 'indene', `col77` = -6964559, `col78` = 4247535.5266884370, `col79` = '20720416124357', `col80` = '2143', `col81` = 4292060102.4466386000, `col82` = 'striving', `col83` = 'boneblack\'s', `col84` = 'redolent', `col85` = 6489697.9009369183, `col86` = 4287473465.9731131000, `col87` = 7726015, `col88` = 'perplexed', `col89` = '17153791', `col90` = 5478587.1108127078, `col91` = 4287091404.7004304000, `col92` = 'Boulez\'s', `col93` = '2931278';
|
||||
CHECK TABLE table0 EXTENDED;
|
||||
|
||||
DROP TABLE table0;
|
||||
set global innodb_file_per_table=@old_innodb_file_per_table;
|
||||
set global innodb_file_format=@old_innodb_file_format;
|
||||
set global innodb_file_format_check=@old_innodb_file_format_check;
|
||||
|
||||
16
mysql-test/t/innodb_bug40360.test
Normal file
16
mysql-test/t/innodb_bug40360.test
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
#
|
||||
# Make sure http://bugs.mysql.com/40360 remains fixed.
|
||||
#
|
||||
|
||||
-- source include/not_embedded.inc
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
SET TX_ISOLATION='READ-COMMITTED';
|
||||
|
||||
# This is the default since MySQL 5.1.29 SET BINLOG_FORMAT='STATEMENT';
|
||||
|
||||
CREATE TABLE bug40360 (a INT) engine=innodb;
|
||||
|
||||
INSERT INTO bug40360 VALUES (1);
|
||||
|
||||
DROP TABLE bug40360;
|
||||
14
mysql-test/t/innodb_bug41904.test
Normal file
14
mysql-test/t/innodb_bug41904.test
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# Make sure http://bugs.mysql.com/41904 remains fixed.
|
||||
#
|
||||
|
||||
-- source include/not_embedded.inc
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
CREATE TABLE bug41904 (id INT PRIMARY KEY, uniquecol CHAR(15)) ENGINE=InnoDB;
|
||||
|
||||
INSERT INTO bug41904 VALUES (1,NULL), (2,NULL);
|
||||
|
||||
CREATE UNIQUE INDEX ui ON bug41904 (uniquecol);
|
||||
|
||||
DROP TABLE bug41904;
|
||||
150
mysql-test/t/innodb_information_schema.test
Normal file
150
mysql-test/t/innodb_information_schema.test
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
#
|
||||
# Test that user data is correctly "visualized" in
|
||||
# INFORMATION_SCHEMA.innodb_locks.lock_data
|
||||
#
|
||||
|
||||
-- source include/have_innodb.inc
|
||||
|
||||
-- disable_query_log
|
||||
-- disable_result_log
|
||||
|
||||
SET storage_engine=InnoDB;
|
||||
|
||||
-- disable_warnings
|
||||
DROP TABLE IF EXISTS t_min, t_max;
|
||||
-- enable_warnings
|
||||
|
||||
let $table_def =
|
||||
(
|
||||
c01 TINYINT,
|
||||
c02 TINYINT UNSIGNED,
|
||||
c03 SMALLINT,
|
||||
c04 SMALLINT UNSIGNED,
|
||||
c05 MEDIUMINT,
|
||||
c06 MEDIUMINT UNSIGNED,
|
||||
c07 INT,
|
||||
c08 INT UNSIGNED,
|
||||
c09 BIGINT,
|
||||
c10 BIGINT UNSIGNED,
|
||||
PRIMARY KEY(c01, c02, c03, c04, c05, c06, c07, c08, c09, c10)
|
||||
);
|
||||
|
||||
-- eval CREATE TABLE t_min $table_def;
|
||||
INSERT INTO t_min VALUES
|
||||
(-128, 0,
|
||||
-32768, 0,
|
||||
-8388608, 0,
|
||||
-2147483648, 0,
|
||||
-9223372036854775808, 0);
|
||||
|
||||
-- eval CREATE TABLE t_max $table_def;
|
||||
INSERT INTO t_max VALUES
|
||||
(127, 255,
|
||||
32767, 65535,
|
||||
8388607, 16777215,
|
||||
2147483647, 4294967295,
|
||||
9223372036854775807, 18446744073709551615);
|
||||
|
||||
CREATE TABLE ```t'\"_str` (
|
||||
c1 VARCHAR(32),
|
||||
c2 VARCHAR(32),
|
||||
c3 VARCHAR(32),
|
||||
c4 VARCHAR(32),
|
||||
c5 VARCHAR(32),
|
||||
c6 VARCHAR(32),
|
||||
c7 VARCHAR(32),
|
||||
PRIMARY KEY(c1, c2, c3, c4, c5, c6, c7)
|
||||
);
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('1', 'abc', '''abc', 'abc''', 'a''bc', 'a''bc''', '''abc''''');
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('2', 'abc', '"abc', 'abc"', 'a"bc', 'a"bc"', '"abc""');
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a\\bc\\', '\\abc\\\\');
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('4', 'abc', 0x00616263, 0x61626300, 0x61006263, 0x6100626300, 0x610062630000);
|
||||
|
||||
-- connect (con_lock,localhost,root,,)
|
||||
-- connect (con_min_trylock,localhost,root,,)
|
||||
-- connect (con_max_trylock,localhost,root,,)
|
||||
-- connect (con_str_insert_supremum,localhost,root,,)
|
||||
-- connect (con_str_lock_row1,localhost,root,,)
|
||||
-- connect (con_str_lock_row2,localhost,root,,)
|
||||
-- connect (con_str_lock_row3,localhost,root,,)
|
||||
-- connect (con_str_lock_row4,localhost,root,,)
|
||||
-- connect (con_verify_innodb_locks,localhost,root,,)
|
||||
|
||||
-- connection con_lock
|
||||
SET autocommit=0;
|
||||
SELECT * FROM t_min FOR UPDATE;
|
||||
SELECT * FROM t_max FOR UPDATE;
|
||||
SELECT * FROM ```t'\"_str` FOR UPDATE;
|
||||
|
||||
-- connection con_min_trylock
|
||||
-- send
|
||||
SELECT * FROM t_min FOR UPDATE;
|
||||
|
||||
-- connection con_max_trylock
|
||||
-- send
|
||||
SELECT * FROM t_max FOR UPDATE;
|
||||
|
||||
-- connection con_str_insert_supremum
|
||||
-- send
|
||||
INSERT INTO ```t'\"_str` VALUES
|
||||
('z', 'z', 'z', 'z', 'z', 'z', 'z');
|
||||
|
||||
-- connection con_str_lock_row1
|
||||
-- send
|
||||
SELECT * FROM ```t'\"_str` WHERE c1 = '1' FOR UPDATE;
|
||||
|
||||
-- connection con_str_lock_row2
|
||||
-- send
|
||||
SELECT * FROM ```t'\"_str` WHERE c1 = '2' FOR UPDATE;
|
||||
|
||||
-- connection con_str_lock_row3
|
||||
-- send
|
||||
SELECT * FROM ```t'\"_str` WHERE c1 = '3' FOR UPDATE;
|
||||
|
||||
-- connection con_str_lock_row4
|
||||
-- send
|
||||
SELECT * FROM ```t'\"_str` WHERE c1 = '4' FOR UPDATE;
|
||||
|
||||
-- connection con_verify_innodb_locks
|
||||
|
||||
# Loop, giving time for the above 2 queries to execute before continuing.
|
||||
# Without this, it sometimes happens that the SELECT FROM innodb_locks
|
||||
# executes before some of them, resulting in less than expected number
|
||||
# of rows being selected from innodb_locks.
|
||||
SET @counter := 0;
|
||||
while (`SELECT (@counter := @counter + 1) <= 50 AND COUNT(*) != 14 FROM INFORMATION_SCHEMA.INNODB_LOCKS`)
|
||||
{
|
||||
sleep 0.1;
|
||||
}
|
||||
|
||||
-- enable_result_log
|
||||
SELECT lock_mode, lock_type, lock_table, lock_index, lock_rec, lock_data
|
||||
FROM INFORMATION_SCHEMA.INNODB_LOCKS ORDER BY lock_data;
|
||||
|
||||
SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS
|
||||
GROUP BY lock_table;
|
||||
|
||||
set @save_sql_mode = @@sql_mode;
|
||||
SET SQL_MODE='ANSI_QUOTES';
|
||||
SELECT lock_table,COUNT(*) FROM INFORMATION_SCHEMA.INNODB_LOCKS
|
||||
GROUP BY lock_table;
|
||||
SET @@sql_mode=@save_sql_mode;
|
||||
-- disable_result_log
|
||||
|
||||
-- connection default
|
||||
|
||||
-- disconnect con_lock
|
||||
-- disconnect con_min_trylock
|
||||
-- disconnect con_max_trylock
|
||||
-- disconnect con_str_insert_supremum
|
||||
-- disconnect con_str_lock_row1
|
||||
-- disconnect con_str_lock_row2
|
||||
-- disconnect con_str_lock_row3
|
||||
-- disconnect con_str_lock_row4
|
||||
-- disconnect con_verify_innodb_locks
|
||||
|
||||
DROP TABLE t_min, t_max, ```t'\"_str`;
|
||||
44
mysql-test/t/innodb_xtradb_bug317074.test
Normal file
44
mysql-test/t/innodb_xtradb_bug317074.test
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
-- source include/have_innodb.inc
|
||||
|
||||
SET @old_innodb_file_format=@@innodb_file_format;
|
||||
SET @old_innodb_file_per_table=@@innodb_file_per_table;
|
||||
SET @old_innodb_file_format_check=@@innodb_file_format_check;
|
||||
SET GLOBAL innodb_file_format='Barracuda';
|
||||
SET GLOBAL innodb_file_per_table=ON;
|
||||
|
||||
-- disable_query_log
|
||||
-- disable_result_log
|
||||
|
||||
DROP TABLE IF EXISTS `test1`;
|
||||
CREATE TABLE IF NOT EXISTS `test1` (
|
||||
`a` int primary key auto_increment,
|
||||
`b` int default 0,
|
||||
`c` char(100) default 'testtest'
|
||||
) ENGINE=InnoDB ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
|
||||
|
||||
delimiter |;
|
||||
CREATE PROCEDURE insert_many(p1 int)
|
||||
BEGIN
|
||||
SET @x = 0;
|
||||
SET @y = 0;
|
||||
REPEAT
|
||||
insert into test1 set b=1;
|
||||
SET @x = @x + 1;
|
||||
SET @y = @y + 1;
|
||||
IF @y >= 100 THEN
|
||||
commit;
|
||||
SET @y = 0;
|
||||
END IF;
|
||||
UNTIL @x >= p1 END REPEAT;
|
||||
END|
|
||||
delimiter ;|
|
||||
call insert_many(100000);
|
||||
DROP PROCEDURE insert_many;
|
||||
|
||||
# The bug is hangup at the following statement
|
||||
ALTER TABLE test1 ENGINE=MyISAM;
|
||||
|
||||
DROP TABLE test1;
|
||||
SET GLOBAL innodb_file_format=@old_innodb_file_format;
|
||||
SET GLOBAL innodb_file_per_table=@old_innodb_file_per_table;
|
||||
SET GLOBAL innodb_file_format_check=@old_innodb_file_format_check;
|
||||
|
|
@ -23,6 +23,16 @@
|
|||
# This is a big test.
|
||||
--source include/big_test.inc
|
||||
|
||||
--echo #
|
||||
--echo # We need big packets.
|
||||
--echo #
|
||||
connect (con1, localhost, root,,);
|
||||
connection con1;
|
||||
SET @old_global_max_allowed_packet=@@global.max_allowed_packet;
|
||||
SET @@global.max_allowed_packet= 1024*1024*1024;
|
||||
connect (con2, localhost, root,,);
|
||||
connection con2;
|
||||
|
||||
--echo #
|
||||
--echo # Preparatory cleanup.
|
||||
--echo #
|
||||
|
|
@ -35,11 +45,6 @@ DROP TABLE IF EXISTS t1;
|
|||
--echo #
|
||||
SET timestamp=1000000000;
|
||||
|
||||
--echo #
|
||||
--echo # We need big packets.
|
||||
--echo #
|
||||
SET @@global.max_allowed_packet= 1024*1024*1024;
|
||||
|
||||
--echo #
|
||||
--echo # Delete all existing binary logs.
|
||||
--echo #
|
||||
|
|
@ -122,9 +127,14 @@ let $MYSQLD_DATADIR= `select @@datadir`;
|
|||
--echo #
|
||||
DROP TABLE t1;
|
||||
|
||||
connection con1;
|
||||
SET @@global.max_allowed_packet=@old_global_max_allowed_packet;
|
||||
|
||||
--echo remove_file \$MYSQLTEST_VARDIR/$mysqlbinlog_output
|
||||
#
|
||||
# NOTE: If you want to see the *huge* mysqlbinlog output, disable next line:
|
||||
#
|
||||
--remove_file $MYSQLTEST_VARDIR/$mysqlbinlog_output
|
||||
|
||||
disconnect con1
|
||||
disconnect con2
|
||||
|
|
|
|||
|
|
@ -27,14 +27,14 @@ UPDATE t1 SET DATA = data*2 WHERE id = 3;
|
|||
|
||||
# grouping/referencing in replace_regex is very slow on long strings,
|
||||
# removing all before/after the interesting row before grouping/referencing
|
||||
--replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/
|
||||
--replace_regex /.*LIST OF TRANSACTIONS FOR EACH SESSION:// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/
|
||||
SHOW ENGINE InnoDB STATUS;
|
||||
|
||||
UPDATE t1 SET data = data*2 WHERE data = 2;
|
||||
|
||||
# grouping/referencing in replace_regex is very slow on long strings,
|
||||
# removing all before/after the interesting row before grouping/referencing
|
||||
--replace_regex /.*---TRANSACTION [0-9]+ [0-9]+, .*, OS thread id [0-9]+// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/
|
||||
--replace_regex /.*LIST OF TRANSACTIONS FOR EACH SESSION:// /MySQL thread id [0-9]+, query id [0-9]+ .*// /.*([0-9]+ lock struct\(s\)), heap size [0-9]+, ([0-9]+ row lock\(s\)).*/\1 \2/
|
||||
SHOW ENGINE InnoDB STATUS;
|
||||
|
||||
SET @@session.tx_isolation = @old_tx_isolation;
|
||||
|
|
|
|||
|
|
@ -41,7 +41,7 @@ create table t1 (a bit) engine=innodb;
|
|||
insert into t1 values (b'0'), (b'1'), (b'000'), (b'100'), (b'001');
|
||||
select hex(a) from t1;
|
||||
# It is not deterministic which duplicate will be seen first
|
||||
--replace_regex /(.*Duplicate entry )'.*'( for key.*)/\1''\2/
|
||||
--replace_regex /entry '(.*)' for/entry '' for/
|
||||
--error ER_DUP_ENTRY
|
||||
alter table t1 add unique (a);
|
||||
drop table t1;
|
||||
|
|
|
|||
|
|
@ -8,19 +8,20 @@
|
|||
# Bug #27322 failure to allocate transaction_prealloc_size causes crash
|
||||
#
|
||||
|
||||
set @pid_temp = (select ID from information_schema.processlist);
|
||||
set session transaction_prealloc_size=1024*1024*1024*1;
|
||||
--replace_column 1 #
|
||||
show processlist;
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
set session transaction_prealloc_size=1024*1024*1024*2;
|
||||
--replace_column 1 #
|
||||
show processlist;
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
--replace_column 1 #
|
||||
set session transaction_prealloc_size=1024*1024*1024*3;
|
||||
--replace_column 1 #
|
||||
show processlist;
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
set session transaction_prealloc_size=1024*1024*1024*4;
|
||||
--replace_column 1 #
|
||||
show processlist;
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
set session transaction_prealloc_size=1024*1024*1024*5;
|
||||
--replace_column 1 #
|
||||
show processlist;
|
||||
select @pid_temp = (select ID from information_schema.processlist) as 'TRUE';
|
||||
|
|
|
|||
|
|
@ -464,3 +464,52 @@ process_flags:
|
|||
err:
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val)
|
||||
{
|
||||
uint length;
|
||||
DBUG_ENTER("init_strvar_from_file");
|
||||
|
||||
if ((length=my_b_gets(f,var, max_size)))
|
||||
{
|
||||
char* last_p = var + length -1;
|
||||
if (*last_p == '\n')
|
||||
*last_p = 0; /* if we stopped on newline, kill it */
|
||||
else
|
||||
{
|
||||
/*
|
||||
If we truncated a line or stopped on last char, remove all chars
|
||||
up to and including newline.
|
||||
*/
|
||||
int c;
|
||||
while (((c=my_b_get(f)) != '\n' && c != my_b_EOF))
|
||||
;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (default_val)
|
||||
{
|
||||
strmake(var, default_val, max_size-1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
|
||||
{
|
||||
char buf[32];
|
||||
DBUG_ENTER("init_intvar_from_file");
|
||||
|
||||
if (my_b_gets(f, buf, sizeof(buf)))
|
||||
{
|
||||
*var = atoi(buf);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (default_val)
|
||||
{
|
||||
*var = default_val;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,38 @@ static inline void remove_from_active_list(safe_mutex_t *mp)
|
|||
mp->prev= mp->next= 0;
|
||||
}
|
||||
|
||||
/*
|
||||
We initialise the hashes for deadlock detection lazily.
|
||||
This greatly helps with performance when lots of mutexes are initiased but
|
||||
only a few of them are actually used (eg. XtraDB).
|
||||
*/
|
||||
static int safe_mutex_lazy_init_deadlock_detection(safe_mutex_t *mp)
|
||||
{
|
||||
if (!my_multi_malloc(MY_FAE | MY_WME,
|
||||
&mp->locked_mutex, sizeof(*mp->locked_mutex),
|
||||
&mp->used_mutex, sizeof(*mp->used_mutex), NullS))
|
||||
{
|
||||
/* Disable deadlock handling for this mutex */
|
||||
mp->create_flags|= MYF_NO_DEADLOCK_DETECTION;
|
||||
mp->active_flags|= MYF_NO_DEADLOCK_DETECTION;
|
||||
return 1; /* Error */
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&THR_LOCK_mutex);
|
||||
mp->id= ++safe_mutex_id;
|
||||
pthread_mutex_unlock(&THR_LOCK_mutex);
|
||||
hash_init(mp->locked_mutex, &my_charset_bin,
|
||||
1000,
|
||||
offsetof(safe_mutex_deadlock_t, id),
|
||||
sizeof(mp->id),
|
||||
0, 0, HASH_UNIQUE);
|
||||
hash_init(mp->used_mutex, &my_charset_bin,
|
||||
1000,
|
||||
offsetof(safe_mutex_t, id),
|
||||
sizeof(mp->id),
|
||||
0, 0, HASH_UNIQUE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int safe_mutex_init(safe_mutex_t *mp,
|
||||
const pthread_mutexattr_t *attr __attribute__((unused)),
|
||||
|
|
@ -168,34 +200,10 @@ int safe_mutex_init(safe_mutex_t *mp,
|
|||
/* Skip the very common '&' prefix from the autogenerated name */
|
||||
mp->name= name[0] == '&' ? name + 1 : name;
|
||||
|
||||
if (safe_mutex_deadlock_detector && !( my_flags & MYF_NO_DEADLOCK_DETECTION))
|
||||
{
|
||||
if (!my_multi_malloc(MY_FAE | MY_WME,
|
||||
&mp->locked_mutex, sizeof(*mp->locked_mutex),
|
||||
&mp->used_mutex, sizeof(*mp->used_mutex), NullS))
|
||||
{
|
||||
/* Disable deadlock handling for this mutex */
|
||||
my_flags|= MYF_NO_DEADLOCK_DETECTION;
|
||||
}
|
||||
else
|
||||
{
|
||||
pthread_mutex_lock(&THR_LOCK_mutex);
|
||||
mp->id= ++safe_mutex_id;
|
||||
pthread_mutex_unlock(&THR_LOCK_mutex);
|
||||
hash_init(mp->locked_mutex, &my_charset_bin,
|
||||
1000,
|
||||
offsetof(safe_mutex_deadlock_t, id),
|
||||
sizeof(mp->id),
|
||||
0, 0, HASH_UNIQUE);
|
||||
hash_init(mp->used_mutex, &my_charset_bin,
|
||||
1000,
|
||||
offsetof(safe_mutex_t, id),
|
||||
sizeof(mp->id),
|
||||
0, 0, HASH_UNIQUE);
|
||||
}
|
||||
}
|
||||
else
|
||||
if (!safe_mutex_deadlock_detector)
|
||||
my_flags|= MYF_NO_DEADLOCK_DETECTION;
|
||||
/* Deadlock detection is initialised only lazily, on first use. */
|
||||
|
||||
mp->create_flags= my_flags;
|
||||
|
||||
#ifdef SAFE_MUTEX_DETECT_DESTROY
|
||||
|
|
@ -310,7 +318,8 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
|
|||
/* Deadlock detection */
|
||||
|
||||
mp->prev= mp->next= 0;
|
||||
if (!(mp->active_flags & (MYF_TRY_LOCK | MYF_NO_DEADLOCK_DETECTION)))
|
||||
if (!(mp->active_flags & (MYF_TRY_LOCK | MYF_NO_DEADLOCK_DETECTION)) &&
|
||||
(mp->used_mutex != NULL || !safe_mutex_lazy_init_deadlock_detection(mp)))
|
||||
{
|
||||
safe_mutex_t **mutex_in_use= my_thread_var_mutex_in_use();
|
||||
|
||||
|
|
@ -643,7 +652,7 @@ int safe_mutex_destroy(safe_mutex_t *mp, const char *file, uint line)
|
|||
void safe_mutex_free_deadlock_data(safe_mutex_t *mp)
|
||||
{
|
||||
/* Free all entries that points to this one */
|
||||
if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION))
|
||||
if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION) && mp->used_mutex != NULL)
|
||||
{
|
||||
pthread_mutex_lock(&THR_LOCK_mutex);
|
||||
my_hash_iterate(mp->used_mutex,
|
||||
|
|
|
|||
|
|
@ -1585,6 +1585,11 @@ mysql_ssl_set(MYSQL *mysql __attribute__((unused)) ,
|
|||
{
|
||||
DBUG_ENTER("mysql_ssl_set");
|
||||
#ifdef HAVE_OPENSSL
|
||||
my_free(mysql->options.ssl_key, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->options.ssl_cert, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->options.ssl_ca, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->options.ssl_capath, MYF(MY_ALLOW_ZERO_PTR));
|
||||
my_free(mysql->options.ssl_cipher, MYF(MY_ALLOW_ZERO_PTR));
|
||||
mysql->options.ssl_key= strdup_if_not_null(key);
|
||||
mysql->options.ssl_cert= strdup_if_not_null(cert);
|
||||
mysql->options.ssl_ca= strdup_if_not_null(ca);
|
||||
|
|
|
|||
|
|
@ -9313,3 +9313,29 @@ st_print_event_info::st_print_event_info()
|
|||
open_cached_file(&body_cache, NULL, NULL, 0, flags);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(MYSQL_SERVER)
|
||||
/*
|
||||
Access to the current replication position.
|
||||
|
||||
There is a dummy replacement for this in the embedded library that returns
|
||||
FALSE; this is used by XtraDB to allow it to access replication stuff while
|
||||
still being able to use the same plugin in both stand-alone and embedded.
|
||||
*/
|
||||
bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
|
||||
const char **group_relay_log_name,
|
||||
ulonglong *relay_log_pos)
|
||||
{
|
||||
#if defined(EMBEDDED_LIBRARY) || !defined(HAVE_REPLICATION)
|
||||
return FALSE;
|
||||
#else
|
||||
const Relay_log_info *rli= &(active_mi->rli);
|
||||
*log_file_name= rli->group_master_log_name;
|
||||
*log_pos= rli->group_master_log_pos +
|
||||
(rli->future_event_relay_log_pos - rli->group_relay_log_pos);
|
||||
*group_relay_log_name= rli->group_relay_log_name;
|
||||
*relay_log_pos= rli->future_event_relay_log_pos;
|
||||
return TRUE;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -3917,6 +3917,10 @@ static inline bool copy_event_cache_to_file_and_reinit(IO_CACHE *cache,
|
|||
reinit_io_cache(cache, WRITE_CACHE, 0, FALSE, TRUE);
|
||||
}
|
||||
|
||||
bool rpl_get_position_info(const char **log_file_name, ulonglong *log_pos,
|
||||
const char **group_relay_log_name,
|
||||
ulonglong *relay_log_pos);
|
||||
|
||||
/**
|
||||
@} (end of group Replication)
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -22,11 +22,6 @@
|
|||
#ifdef HAVE_REPLICATION
|
||||
|
||||
|
||||
// Defined in slave.cc
|
||||
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
|
||||
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val);
|
||||
|
||||
Master_info::Master_info()
|
||||
:Slave_reporting_capability("I/O"),
|
||||
ssl(0), ssl_verify_server_cert(0), fd(-1), io_thd(0), inited(0),
|
||||
|
|
|
|||
|
|
@ -23,11 +23,6 @@
|
|||
|
||||
static int count_relay_log_space(Relay_log_info* rli);
|
||||
|
||||
// Defined in slave.cc
|
||||
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val);
|
||||
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val);
|
||||
|
||||
|
||||
Relay_log_info::Relay_log_info()
|
||||
:Slave_reporting_capability("SQL"),
|
||||
|
|
|
|||
51
sql/slave.cc
51
sql/slave.cc
|
|
@ -755,57 +755,6 @@ const char *print_slave_db_safe(const char* db)
|
|||
DBUG_RETURN((db ? db : ""));
|
||||
}
|
||||
|
||||
int init_strvar_from_file(char *var, int max_size, IO_CACHE *f,
|
||||
const char *default_val)
|
||||
{
|
||||
uint length;
|
||||
DBUG_ENTER("init_strvar_from_file");
|
||||
|
||||
if ((length=my_b_gets(f,var, max_size)))
|
||||
{
|
||||
char* last_p = var + length -1;
|
||||
if (*last_p == '\n')
|
||||
*last_p = 0; // if we stopped on newline, kill it
|
||||
else
|
||||
{
|
||||
/*
|
||||
If we truncated a line or stopped on last char, remove all chars
|
||||
up to and including newline.
|
||||
*/
|
||||
int c;
|
||||
while (((c=my_b_get(f)) != '\n' && c != my_b_EOF))
|
||||
;
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (default_val)
|
||||
{
|
||||
strmake(var, default_val, max_size-1);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
|
||||
int init_intvar_from_file(int* var, IO_CACHE* f, int default_val)
|
||||
{
|
||||
char buf[32];
|
||||
DBUG_ENTER("init_intvar_from_file");
|
||||
|
||||
|
||||
if (my_b_gets(f, buf, sizeof(buf)))
|
||||
{
|
||||
*var = atoi(buf);
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
else if (default_val)
|
||||
{
|
||||
*var = default_val;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
|
||||
/*
|
||||
Note that we rely on the master's version (3.23, 4.0.14 etc) instead of
|
||||
relying on the binlog's version. This is not perfect: imagine an upgrade
|
||||
|
|
|
|||
|
|
@ -5333,6 +5333,7 @@ compare_tables(TABLE *table,
|
|||
!table->s->mysql_version ||
|
||||
(table->s->frm_version < FRM_VER_TRUE_VARCHAR && varchar))
|
||||
{
|
||||
DBUG_PRINT("info", ("Basic checks -> ALTER_TABLE_DATA_CHANGED"));
|
||||
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
|
@ -5361,6 +5362,8 @@ compare_tables(TABLE *table,
|
|||
if ((tmp_new_field->flags & NOT_NULL_FLAG) !=
|
||||
(uint) (field->flags & NOT_NULL_FLAG))
|
||||
{
|
||||
DBUG_PRINT("info", ("NULL behaviour difference in field '%s' -> "
|
||||
"ALTER_TABLE_DATA_CHANGED", new_field->field_name));
|
||||
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
|
@ -5382,6 +5385,8 @@ compare_tables(TABLE *table,
|
|||
/* Evaluate changes bitmap and send to check_if_incompatible_data() */
|
||||
if (!(tmp= field->is_equal(tmp_new_field)))
|
||||
{
|
||||
DBUG_PRINT("info", ("!field_is_equal('%s') -> ALTER_TABLE_DATA_CHANGED",
|
||||
new_field->field_name));
|
||||
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
|
@ -5515,16 +5520,22 @@ compare_tables(TABLE *table,
|
|||
/* Check if changes are compatible with current handler without a copy */
|
||||
if (table->file->check_if_incompatible_data(create_info, changes))
|
||||
{
|
||||
DBUG_PRINT("info", ("check_if_incompatible_data() -> "
|
||||
"ALTER_TABLE_DATA_CHANGED"));
|
||||
*need_copy_table= ALTER_TABLE_DATA_CHANGED;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (*index_drop_count || *index_add_count)
|
||||
{
|
||||
DBUG_PRINT("info", ("Index dropped=%u added=%u -> "
|
||||
"ALTER_TABLE_INDEX_CHANGED",
|
||||
*index_drop_count, *index_add_count));
|
||||
*need_copy_table= ALTER_TABLE_INDEX_CHANGED;
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
DBUG_PRINT("info", (" -> ALTER_TABLE_METADATA_ONLY"));
|
||||
*need_copy_table= ALTER_TABLE_METADATA_ONLY; // Tables are compatible
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
|
|
|||
97
storage/xtradb/CMakeLists.txt
Normal file
97
storage/xtradb/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
# Copyright (C) 2006 MySQL 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
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
|
||||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -DSAFEMALLOC -DSAFE_MUTEX")
|
||||
ADD_DEFINITIONS(-D_WIN32 -D_LIB)
|
||||
|
||||
# Bug 19424 - InnoDB: Possibly a memory overrun of the buffer being freed (64-bit Visual C)
|
||||
# Removing Win64 compiler optimizations for all innodb/mem/* files.
|
||||
IF(CMAKE_GENERATOR MATCHES "Visual Studio" AND CMAKE_SIZEOF_VOID_P MATCHES 8)
|
||||
SET_SOURCE_FILES_PROPERTIES(${CMAKE_SOURCE_DIR}/storage/xtradb/mem/mem0mem.c
|
||||
${CMAKE_SOURCE_DIR}/storage/xtradb/mem/mem0pool.c
|
||||
PROPERTIES COMPILE_FLAGS -Od)
|
||||
ENDIF(CMAKE_GENERATOR MATCHES "Visual Studio" AND CMAKE_SIZEOF_VOID_P MATCHES 8)
|
||||
|
||||
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/include ${CMAKE_SOURCE_DIR}/zlib
|
||||
${CMAKE_SOURCE_DIR}/storage/xtradb/include
|
||||
${CMAKE_SOURCE_DIR}/storage/xtradb/handler
|
||||
${CMAKE_SOURCE_DIR}/sql
|
||||
${CMAKE_SOURCE_DIR}/regex
|
||||
${CMAKE_SOURCE_DIR}/extra/yassl/include)
|
||||
|
||||
SET(INNOBASE_SOURCES btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c btr/btr0sea.c
|
||||
buf/buf0buddy.c buf/buf0buf.c buf/buf0flu.c buf/buf0lru.c buf/buf0rea.c
|
||||
data/data0data.c data/data0type.c
|
||||
dict/dict0boot.c dict/dict0crea.c dict/dict0dict.c dict/dict0load.c dict/dict0mem.c
|
||||
dyn/dyn0dyn.c
|
||||
eval/eval0eval.c eval/eval0proc.c
|
||||
fil/fil0fil.c
|
||||
fsp/fsp0fsp.c
|
||||
fut/fut0fut.c fut/fut0lst.c
|
||||
ha/ha0ha.c ha/hash0hash.c ha/ha0storage.c
|
||||
ibuf/ibuf0ibuf.c
|
||||
pars/lexyy.c pars/pars0grm.c pars/pars0opt.c pars/pars0pars.c pars/pars0sym.c
|
||||
lock/lock0lock.c lock/lock0iter.c
|
||||
log/log0log.c log/log0recv.c
|
||||
mach/mach0data.c
|
||||
mem/mem0mem.c mem/mem0pool.c
|
||||
mtr/mtr0log.c mtr/mtr0mtr.c
|
||||
os/os0file.c os/os0proc.c os/os0sync.c os/os0thread.c
|
||||
page/page0cur.c page/page0page.c page/page0zip.c
|
||||
que/que0que.c
|
||||
handler/ha_innodb.cc handler/handler0alter.cc handler/i_s.cc handler/mysql_addons.cc
|
||||
read/read0read.c
|
||||
rem/rem0cmp.c rem/rem0rec.c
|
||||
row/row0ext.c row/row0ins.c row/row0merge.c row/row0mysql.c
|
||||
row/row0purge.c row/row0row.c row/row0sel.c row/row0uins.c
|
||||
row/row0umod.c row/row0undo.c row/row0upd.c row/row0vers.c
|
||||
srv/srv0que.c srv/srv0srv.c srv/srv0start.c
|
||||
sync/sync0arr.c sync/sync0rw.c sync/sync0sync.c
|
||||
thr/thr0loc.c
|
||||
trx/trx0i_s.c trx/trx0purge.c trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c
|
||||
trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c
|
||||
usr/usr0sess.c
|
||||
ut/ut0byte.c ut/ut0dbg.c ut/ut0mem.c ut/ut0rnd.c ut/ut0ut.c ut/ut0vec.c ut/ut0list.c ut/ut0wqueue.c)
|
||||
|
||||
IF(NOT SOURCE_SUBLIBS)
|
||||
ADD_LIBRARY(innobase ${INNOBASE_SOURCES})
|
||||
ADD_DEPENDENCIES(innobase GenError)
|
||||
SET_TARGET_PROPERTIES(innobase PROPERTIES COMPILE_FLAGS "-DMYSQL_SERVER")
|
||||
|
||||
IF(INNODB_DYNAMIC_PLUGIN)
|
||||
# The dynamic plugin requires CMake 2.6.0 or later. Otherwise, the /DELAYLOAD property
|
||||
# will not be set
|
||||
CMAKE_MINIMUM_REQUIRED(VERSION 2.6.0 FATAL_ERROR)
|
||||
ADD_LIBRARY(ha_innodb SHARED ${INNOBASE_SOURCES} ha_innodb.def handler/win_delay_loader.cc)
|
||||
ADD_DEPENDENCIES(ha_innodb GenError mysqld)
|
||||
# If build type is not specified as Release, default to Debug
|
||||
# This is a workaround to a problem in CMake 2.6, which does not
|
||||
# set the path of mysqld.lib correctly
|
||||
IF(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
SET(CMAKE_BUILD_TYPE "Release")
|
||||
ELSE(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
SET(CMAKE_BUILD_TYPE "Debug")
|
||||
ENDIF(CMAKE_BUILD_TYPE MATCHES Release)
|
||||
TARGET_LINK_LIBRARIES(ha_innodb strings zlib)
|
||||
TARGET_LINK_LIBRARIES(ha_innodb ${CMAKE_SOURCE_DIR}/sql/${CMAKE_BUILD_TYPE}/mysqld.lib)
|
||||
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES OUTPUT_NAME ha_innodb)
|
||||
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES LINK_FLAGS "/MAP /MAPINFO:EXPORTS")
|
||||
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES LINK_FLAGS "/ENTRY:\"_DllMainCRTStartup@12\"")
|
||||
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES COMPILE_FLAGS "-DMYSQL_DYNAMIC_PLUGIN")
|
||||
SET_TARGET_PROPERTIES(ha_innodb PROPERTIES LINK_FLAGS "/DELAYLOAD:mysqld.exe")
|
||||
ENDIF(INNODB_DYNAMIC_PLUGIN)
|
||||
|
||||
ENDIF(NOT SOURCE_SUBLIBS)
|
||||
30
storage/xtradb/COPYING.Google
Normal file
30
storage/xtradb/COPYING.Google
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
Portions of this software contain modifications contributed by Google, Inc.
|
||||
These contributions are used with the following license:
|
||||
|
||||
Copyright (c) 2008, Google Inc. All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions
|
||||
are met:
|
||||
* Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above
|
||||
copyright notice, this list of conditions and the following
|
||||
disclaimer in the documentation and/or other materials
|
||||
provided with the distribution.
|
||||
* Neither the name of the Google Inc. nor the names of its
|
||||
contributors may be used to endorse or promote products
|
||||
derived from this software without specific prior written
|
||||
permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
775
storage/xtradb/ChangeLog
Normal file
775
storage/xtradb/ChangeLog
Normal file
|
|
@ -0,0 +1,775 @@
|
|||
2009-03-05 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
|
||||
mysql-test/innodb-autoinc.test:
|
||||
Fix Bug#43203 Overflow from auto incrementing causes server segv
|
||||
|
||||
2009-02-25 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
|
||||
mysql-test/innodb-autoinc.test:
|
||||
Fix Bug#42714 AUTO_INCREMENT errors in 5.1.31
|
||||
|
||||
2009-02-23 The InnoDB Team
|
||||
|
||||
* btr/btr0cur.c:
|
||||
Fix Bug#43043 Crash on BLOB delete operation
|
||||
|
||||
2009-02-20 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Make innodb_use_sys_malloc=ON the default.
|
||||
|
||||
2009-02-20 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
|
||||
mysql-test/innodb-autoinc.test:
|
||||
Fix Bug#42400 InnoDB autoinc code can't handle floating-point columns
|
||||
|
||||
2009-02-18 The InnoDB Team
|
||||
|
||||
* include/ut0mem.h, os/os0proc.c, ut/ut0mem.c:
|
||||
Protect ut_total_allocated_memory with ut_list_mutex in
|
||||
os_mem_alloc_large() and os_mem_free_large(). The lack of this mutex
|
||||
protection could cause an assertion failure during fast index
|
||||
creation. Also, add UNIV_MEM_ALLOC and UNIV_MEM_FREE instrumentation
|
||||
to os_mem_alloc_large() and os_mem_free_large(), so that Valgrind can
|
||||
detect more errors.
|
||||
|
||||
2009-02-11 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Make innodb_thread_concurrency=0 the default. The old default value
|
||||
was 8. A non-zero setting may be useful when InnoDB is showing severe
|
||||
scalability problems under multiple concurrent connections.
|
||||
|
||||
2009-02-10 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, handler/ha_innodb.h:
|
||||
Fix Bug#41676 Table names are case insensitive in locking
|
||||
|
||||
2009-02-10 The InnoDB Team
|
||||
|
||||
* mem/mem0dbg.c, mem/mem0mem.c, mem/mem0pool.c:
|
||||
When innodb_use_sys_malloc is set, ignore
|
||||
innodb_additional_mem_pool_size, because nothing will be allocated
|
||||
from mem_comm_pool.
|
||||
|
||||
2009-02-10 The InnoDB Team
|
||||
|
||||
* ut/ut0mem.c:
|
||||
Map ut_malloc_low(), ut_realloc(), and ut_free() directly to malloc(),
|
||||
realloc(), and free() when innodb_use_sys_malloc is set. As a side
|
||||
effect, ut_total_allocated_memory ("Total memory allocated" in the
|
||||
"BUFFER POOL AND MEMORY" section of SHOW ENGINE INNODB STATUS) will
|
||||
exclude any memory allocated by these functions when
|
||||
innodb_use_sys_malloc is set.
|
||||
|
||||
2009-02-10 The InnoDB Team
|
||||
|
||||
* btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc,
|
||||
include/buf0buf.ic, include/os0sync.h, include/srv0srv.h,
|
||||
include/sync0rw.h, include/sync0rw.ic, include/sync0sync.h,
|
||||
include/sync0sync.ic, include/univ.i, row/row0sel.c, srv/srv0srv.c,
|
||||
srv/srv0start.c, sync/sync0arr.c, sync/sync0rw.c, sync/sync0sync.c:
|
||||
On those platforms that support it, implement the synchronization
|
||||
primitives of InnoDB mutexes and read/write locks with GCC atomic
|
||||
builtins instead of Pthreads mutexes and InnoDB mutexes. These changes
|
||||
are based on a patch supplied by Mark Callaghan of Google under a BSD
|
||||
license.
|
||||
|
||||
2009-01-30 The InnoDB Team
|
||||
|
||||
* btr/btr0cur.c, btr/btr0sea.c, buf/buf0buf.c, handler/ha_innodb.cc,
|
||||
include/btr0sea.h, include/buf0buf.h, include/sync0sync.h,
|
||||
sync/sync0sync.c:
|
||||
Make the configuration parameter innodb_adaptive_hash_index dynamic,
|
||||
so that it can be changed at runtime.
|
||||
|
||||
2009-01-29 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, ibuf/ibuf0ibuf.c, include/ibuf0ibuf.h,
|
||||
include/ibuf0ibuf.ic:
|
||||
Implement the settable global variable innodb_change_buffering,
|
||||
with the allowed values 'none' and 'inserts'. The default value
|
||||
'inserts' enables the buffering of inserts to non-unique secondary
|
||||
index trees when the B-tree leaf page is not in the buffer pool.
|
||||
|
||||
2009-01-27 The InnoDB Team
|
||||
|
||||
* buf/buf0lru.c:
|
||||
Fix a race condition in buf_LRU_invalidate_tablespace(): The
|
||||
compressed page size (zip_size) was read while the block descriptor
|
||||
was no longer protected by a mutex. This could lead to corruption
|
||||
when a table is dropped on a busy system that contains compressed
|
||||
tables.
|
||||
|
||||
2009-01-26 The InnoDB Team
|
||||
|
||||
* btr/btr0sea.c, buf/buf0buf.c, include/buf0buf.h, include/buf0buf.ic,
|
||||
include/mtr0log.ic, include/row0upd.ic, mtr/mtr0mtr.c:
|
||||
Implement buf_block_align() with pointer arithmetics, as it is in the
|
||||
built-in InnoDB distributed with MySQL. Do not acquire the buffer pool
|
||||
mutex before buf_block_align(). This removes a scalability bottleneck
|
||||
in the adaptive hash index lookup. In CHECK TABLE, check that
|
||||
buf_pool->page_hash is consistent with buf_block_align().
|
||||
|
||||
2009-01-23 The InnoDB Team
|
||||
|
||||
* btr/btr0sea.c:
|
||||
Fix Bug#42279 Race condition in btr_search_drop_page_hash_when_freed()
|
||||
|
||||
2009-01-23 The InnoDB Team
|
||||
|
||||
* buf/buf0buf.c, include/buf0buf.h:
|
||||
Remove the unused mode BUF_GET_NOWAIT of buf_page_get_gen()
|
||||
|
||||
2009-01-20 The InnoDB Team
|
||||
|
||||
* include/rem0rec.h, include/rem0rec.ic:
|
||||
Fix Bug#41571 MySQL segfaults after innodb recovery
|
||||
|
||||
2009-01-20 The InnoDB Team
|
||||
|
||||
* lock/lock0lock.c:
|
||||
Fix Bug#42152 Race condition in lock_is_table_exclusive()
|
||||
|
||||
2009-01-14 The InnoDB Team
|
||||
|
||||
* include/trx0roll.h, trx/trx0roll.c, trx/trx0trx.c:
|
||||
Fix Bug#38187 Error 153 when creating savepoints
|
||||
|
||||
2009-01-14 The InnoDB Team
|
||||
|
||||
* dict/dict0load.c:
|
||||
Fix Bug#42075 dict_load_indexes failure in dict_load_table will
|
||||
corrupt the dictionary cache
|
||||
|
||||
2009-01-13 The InnoDB Team
|
||||
|
||||
* buf/buf0buddy.c, dict/dict0dict.c, dict/dict0mem.c, fil/fil0fil.c,
|
||||
ha/ha0storage.c, handler/ha_innodb.cc, handler/win_delay_loader.cc,
|
||||
include/buf0buf.ic, include/dict0dict.ic, include/hash0hash.h,
|
||||
thr/thr0loc.c, trx/trx0i_s.c:
|
||||
Add the parameter ASSERTION to HASH_SEARCH() macro, and use it for
|
||||
light validation of the traversed items in hash table lookups when
|
||||
UNIV_DEBUG is enabled.
|
||||
|
||||
2009-01-09 The InnoDB Team
|
||||
|
||||
* buf/buf0flu.c, include/buf0flu.h, include/buf0flu.ic:
|
||||
Remove unused code from the functions
|
||||
buf_flush_insert_into_flush_list() and
|
||||
buf_flush_insert_sorted_into_flush_list().
|
||||
|
||||
2009-01-09 The InnoDB Team
|
||||
|
||||
* buf/buf0flu.c:
|
||||
Simplify the functions buf_flush_try_page() and buf_flush_batch(). Add
|
||||
debug assertions and an explanation to buf_flush_write_block_low().
|
||||
|
||||
2009-01-07 The InnoDB Team
|
||||
|
||||
* row/row0merge.c:
|
||||
Fix a bug in recovery when dropping temporary indexes.
|
||||
|
||||
2009-01-07 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, handler/ha_innodb.h, handler/handler0alter.cc:
|
||||
Fix Bug#41680 calls to trx_allocate_for_mysql are not consistent
|
||||
|
||||
2009-01-07 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb_bug41904.result, mysql-test/innodb_bug41904.test,
|
||||
row/row0merge.c:
|
||||
Fix Bug#41904 create unique index problem
|
||||
|
||||
2009-01-02 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, include/srv0srv.h, mem/mem0pool.c,
|
||||
mysql-test/innodb-use-sys-malloc-master.opt,
|
||||
mysql-test/innodb-use-sys-malloc.result,
|
||||
mysql-test/innodb-use-sys-malloc.test, srv/srv0srv.c, srv/srv0start.c:
|
||||
Implement the configuration parameter innodb_use_sys_malloc (false by
|
||||
default), for disabling InnoDB's internal memory allocator and using
|
||||
system malloc/free instead. The "BUFFER POOL AND MEMORY" section of
|
||||
SHOW ENGINE INNODB STATUS will report "in additional pool allocated
|
||||
allocated 0" when innodb_use_sys_malloc is set.
|
||||
|
||||
2008-12-30 The InnoDB Team
|
||||
|
||||
* btr/btr0btr.c:
|
||||
When setting the PAGE_LEVEL of a compressed B-tree page from or to 0,
|
||||
compress the page at the same time. This is necessary, because the
|
||||
column information stored on the compressed page will differ between
|
||||
leaf and non-leaf pages. Leaf pages are identified by PAGE_LEVEL=0.
|
||||
This bug can make InnoDB crash when all rows of a compressed table are
|
||||
deleted.
|
||||
|
||||
2008-12-17 The InnoDB Team
|
||||
|
||||
* include/row0sel.h, include/row0upd.h, pars/pars0pars.c,
|
||||
row/row0mysql.c, row/row0sel.c, row/row0upd.c:
|
||||
Remove update-in-place select from the internal SQL interpreter. It
|
||||
was only used for updating the InnoDB internal data dictionary when
|
||||
renaming or dropping tables. It could have caused deadlocks when
|
||||
acquiring latches on insert buffer bitmap pages.
|
||||
|
||||
2008-12-17 The InnoDB Team
|
||||
|
||||
* btr/btr0sea.c, buf/buf0buf.c, buf/buf0lru.c, ha/ha0ha.c,
|
||||
ha/hash0hash.c, include/buf0buf.h, include/ha0ha.h, include/ha0ha.ic,
|
||||
include/hash0hash.h, include/univ.i:
|
||||
Introduce the preprocessor symbol UNIV_AHI_DEBUG for enabling adaptive
|
||||
hash index debugging independently of UNIV_DEBUG.
|
||||
|
||||
2008-12-16 The InnoDB Team
|
||||
|
||||
* btr/btr0cur.c:
|
||||
Do not update the free bits in the insert buffer bitmap when inserting
|
||||
or deleting from the insert buffer B-tree. Assert that records in the
|
||||
insert buffer B-tree are never updated.
|
||||
|
||||
2008-12-12 The InnoDB Team
|
||||
|
||||
* buf/buf0buf.c, fil/fil0fil.c, fsp/fsp0fsp.c, ibuf/ibuf0ibuf.c,
|
||||
include/fil0fil.h, include/ibuf0ibuf.h, include/ibuf0ibuf.ic,
|
||||
include/ibuf0types.h:
|
||||
Clean up the insert buffer subsystem so that only one insert
|
||||
buffer B-tree exists.
|
||||
Originally, there were provisions in InnoDB for multiple insert
|
||||
buffer B-trees, apparently one for each tablespace.
|
||||
When Heikki Tuuri implemented multiple InnoDB tablespaces in
|
||||
MySQL/InnoDB 4.1, he made the insert buffer live only in the
|
||||
system tablespace (space 0) but left the provisions in the code.
|
||||
|
||||
2008-12-11 The InnoDB Team
|
||||
|
||||
* include/srv0srv.h, os/os0proc.c, srv/srv0srv.c:
|
||||
Fix the issue that the InnoDB plugin fails if innodb_buffer_pool_size
|
||||
is defined bigger than 4096M on 64-bit Windows. This bug should not
|
||||
have affected other 64-bit systems.
|
||||
|
||||
2008-12-09 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Fix Bug#40386 Not flushing query cache after truncate.
|
||||
|
||||
2008-12-09 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, srv/srv0srv.c, trx/trx0trx.c:
|
||||
Fix Bug#40760 "set global innodb_thread_concurrency = 0;" is not safe
|
||||
|
||||
2008-12-04 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, handler/mysql_addons.cc,
|
||||
include/mysql_addons.h, trx/trx0i_s.c, win-plugin/win-plugin.diff:
|
||||
Remove dependencies to MySQL internals (defining MYSQL_SERVER).
|
||||
|
||||
2008-12-02 The InnoDB Team
|
||||
|
||||
* page/page0cur.c:
|
||||
When allocating space for a record from the free list of previously
|
||||
purged records, zero out the DB_TRX_ID and DB_ROLL_PTR of the purged
|
||||
record if the new record would not overwrite these fields. This fixes
|
||||
a harmless content mismatch reported by page_zip_validate().
|
||||
|
||||
2008-12-02 The InnoDB Team
|
||||
|
||||
* row/row0merge.c:
|
||||
Replace the WHILE 1 with WHILE 1=1 in the SQL procedure, so that the
|
||||
loop will actually be entered and temporary indexes be dropped during
|
||||
crash recovery.
|
||||
|
||||
2008-12-01 The InnoDB Team
|
||||
|
||||
InnoDB Plugin 1.0.2 released
|
||||
|
||||
2008-10-31 The InnoDB Team
|
||||
|
||||
* dict/dict0mem.c, include/dict0mem.h, include/lock0lock.h,
|
||||
include/row0mysql.h, include/trx0trx.h, include/univ.i,
|
||||
include/ut0vec.h, include/ut0vec.ic, lock/lock0lock.c,
|
||||
row/row0mysql.c, trx/trx0trx.c:
|
||||
Fix Bug#26316 Triggers create duplicate entries on auto-increment
|
||||
columns
|
||||
|
||||
2008-10-30 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, handler/handler0vars.h,
|
||||
handler/win_delay_loader.cc, mysql-test/innodb_bug40360.result,
|
||||
mysql-test/innodb_bug40360.test:
|
||||
Fix Bug#40360 Binlog related errors with binlog off
|
||||
|
||||
2008-10-29 The InnoDB Team
|
||||
|
||||
* include/data0type.ic:
|
||||
Fix Bug#40369 dtype_get_sql_null_size() returns 0 or 1, not the size
|
||||
|
||||
2008-10-29 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, include/srv0srv.h, srv/srv0srv.c:
|
||||
Fix Bug#38189 innodb_stats_on_metadata missing
|
||||
|
||||
2008-10-28 The InnoDB Team
|
||||
|
||||
* CMakeLists.txt, ha_innodb.def, handler/ha_innodb.cc,
|
||||
handler/handler0alter.cc, handler/handler0vars.h, handler/i_s.cc,
|
||||
handler/win_delay_loader.cc, win-plugin/*:
|
||||
Implemented the delayloading of externals for the plugin on Windows.
|
||||
This makes it possible to build a dynamic plugin (ha_innodb.dll) on
|
||||
Windows.
|
||||
|
||||
2008-10-27 The InnoDB Team
|
||||
|
||||
* CMakeLists.txt:
|
||||
Fix Bug#19424 InnoDB: Possibly a memory overrun of the buffer being
|
||||
freed (64-bit Visual C)
|
||||
|
||||
2008-10-23 The InnoDB Team
|
||||
|
||||
* ibuf/ibuf0ibuf.c:
|
||||
ibuf_delete_rec(): When the cursor to the insert buffer record
|
||||
cannot be restored, do not complain if the tablespace does not
|
||||
exist, because the insert buffer record may have been discarded by
|
||||
some other thread. This bug has existed in MySQL/InnoDB since
|
||||
version 4.1, when innodb_file_per_table was implemented.
|
||||
This may fix Bug#27276 InnoDB Error: ibuf cursor restoration fails.
|
||||
|
||||
2008-10-22 The InnoDB Team
|
||||
|
||||
* dict/dict0dict.c, dict/dict0mem.c, handler/ha_innodb.cc,
|
||||
handler/ha_innodb.h, include/dict0dict.h, include/dict0mem.h,
|
||||
row/row0mysql.c:
|
||||
Fix Bug#39830 Table autoinc value not updated on first insert
|
||||
Fix Bug#35498 Cannot get table test/table1 auto-inccounter value in
|
||||
::info
|
||||
Fix Bug#36411 "Failed to read auto-increment value from storage
|
||||
engine" in 5.1.24 auto-inc
|
||||
|
||||
2008-10-22 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, include/row0mysql.h, row/row0mysql.c:
|
||||
Fix Bug#40224 New AUTOINC changes mask reporting of deadlock/timeout
|
||||
errors
|
||||
|
||||
2008-10-16 The InnoDB Team
|
||||
|
||||
* dict/dict0dict.c, mysql-test/innodb-index.result,
|
||||
mysql-test/innodb-index.test:
|
||||
Skip the undo log size check when creating REDUNDANT and COMPACT
|
||||
tables. In ROW_FORMAT=DYNAMIC and ROW_FORMAT=COMPRESSED, column
|
||||
prefix indexes require that prefixes of externally stored columns
|
||||
be written to the undo log. This may make the undo log record
|
||||
bigger than the record on the B-tree page. The maximum size of an
|
||||
undo log record is the page size. That must be checked for, in
|
||||
dict_index_add_to_cache(). However, this restriction must not
|
||||
be enforced on REDUNDANT or COMPACT tables.
|
||||
|
||||
2008-10-15 The InnoDB Team
|
||||
|
||||
* btr/btr0cur.c, include/btr0cur.h, row/row0ext.c, row/row0sel.c,
|
||||
row/row0upd.c:
|
||||
When the server crashes while freeing an externally stored column
|
||||
of a compressed table, the BTR_EXTERN_LEN field in the BLOB
|
||||
pointer will be written as 0. Tolerate this in the functions that
|
||||
deal with externally stored columns. This fixes problems after
|
||||
crash recovery, in the rollback of incomplete transactions, and in
|
||||
the purge of delete-marked records.
|
||||
|
||||
2008-10-15 The InnoDB Team
|
||||
|
||||
* btr/btr0btr.c, include/page0zip.h, page/page0zip.c, include/univ.i:
|
||||
When a B-tree node of a compressed table is split or merged, the
|
||||
compression may fail. In this case, the entire compressed page
|
||||
will be copied and the excess records will be deleted. However,
|
||||
page_zip_copy(), now renamed to page_zip_copy_recs(), copied too
|
||||
many fields in the page header, overwriting PAGE_BTR_SEG_LEAF and
|
||||
PAGE_BTR_SEG_TOP when splitting the B-tree root. This caused
|
||||
corruption of compressed tables. Furthermore, the lock table and
|
||||
the adaptive hash index would be corrupted, because we forgot to
|
||||
update them when invoking page_zip_copy_recs().
|
||||
|
||||
Introduce the symbol UNIV_ZIP_DEBUG for triggering the copying of
|
||||
compressed pages more often, for debugging purposes.
|
||||
|
||||
2008-10-10 The InnoDB Team
|
||||
|
||||
* handler/handler0alter.cc, include/row0merge.h, row/row0merge.c,
|
||||
row/row0mysql.c:
|
||||
Fix some locking issues, mainly in fast index creation. The
|
||||
InnoDB data dictionary cache should be latched whenever a
|
||||
transaction is holding locks on any data dictionary tables.
|
||||
Otherwise, lock waits or deadlocks could occur. Furthermore, the
|
||||
data dictionary transaction must be committed (and the locks
|
||||
released) before the data dictionary latch is released.
|
||||
|
||||
ha_innobase::add_index(): Lock the data dictionary before renaming
|
||||
or dropping the created indexes, because neither operation will
|
||||
commit the data dictionary transaction.
|
||||
|
||||
ha_innobase::final_drop_index(): Commit the transactions before
|
||||
unlocking the data dictionary.
|
||||
|
||||
2008-10-09 The InnoDB Team
|
||||
|
||||
* buf/buf0lru.c:
|
||||
Fix Bug#39939 DROP TABLE/DISCARD TABLESPACE takes long time in
|
||||
buf_LRU_invalidate_tablespace()
|
||||
|
||||
2008-10-08 The InnoDB Team
|
||||
|
||||
* dict/dict0crea.c, trx/trx0roll.c, include/row0mysql.h,
|
||||
row/row0merge.c, row/row0mysql.c:
|
||||
When dropping a table, hold the data dictionary latch until the
|
||||
transaction has been committed. The data dictionary latch is
|
||||
supposed to prevent lock waits and deadlocks in the data
|
||||
dictionary tables. Due to this bug, DROP TABLE could cause a
|
||||
deadlock or hang. Note that because of Bug#33650 and Bug#39833,
|
||||
MySQL may also drop a (temporary) table when executing CREATE INDEX
|
||||
or ALTER TABLE ... ADD INDEX.
|
||||
|
||||
2008-10-04 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb_bug39438-master.opt,
|
||||
mysql-test/innodb_bug39438.result, mysql-test/innodb_bug39438.test:
|
||||
Fix Bug#39438 Testcase for Bug#39436 crashes on 5.1 in
|
||||
fil_space_get_latch
|
||||
|
||||
2008-10-04 The InnoDB Team
|
||||
|
||||
* include/lock0lock.h, lock/lock0lock.c,
|
||||
mysql-test/innodb_bug38231.result, mysql-test/innodb_bug38231.test,
|
||||
row/row0mysql.c:
|
||||
Fix Bug#38231 Innodb crash in lock_reset_all_on_table() on TRUNCATE +
|
||||
LOCK / UNLOCK
|
||||
|
||||
2008-10-04 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Fix Bug#35498 Cannot get table test/table1 auto-inccounter value in
|
||||
::info
|
||||
|
||||
2008-10-04 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, handler/ha_innodb.h:
|
||||
Fix Bug#37788 InnoDB Plugin: AUTO_INCREMENT wrong for compressed
|
||||
tables
|
||||
|
||||
2008-10-04 The InnoDB Team
|
||||
|
||||
* dict/dict0dict.c, handler/ha_innodb.cc, handler/ha_innodb.h,
|
||||
include/dict0dict.h, include/dict0mem.h, row/row0mysql.c:
|
||||
Fix Bug#39830 Table autoinc value not updated on first insert
|
||||
|
||||
2008-10-03 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb-index.test, mysql-test/innodb-index.result,
|
||||
mysql-test/innodb-timeout.test, mysql-test/innodb-timeout.result,
|
||||
srv/srv0srv.c, include/srv0srv.h, handler/ha_innodb.cc,
|
||||
include/ha_prototypes.h:
|
||||
Fix Bug#36285 innodb_lock_wait_timeout is not dynamic, not per session
|
||||
|
||||
2008-09-19 The InnoDB Team
|
||||
|
||||
* os/os0proc.c:
|
||||
Fix a memory leak on Windows. The memory leak was due to wrong
|
||||
parameters passed into VirtualFree() call. As the result, the
|
||||
call fails with Windows error 87.
|
||||
|
||||
2008-09-17 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb.result, mysql-test/innodb-zip.result,
|
||||
mysql-test/innodb-zip.test, mysql-test/innodb.test, ibuf/ibuf0ibuf.c,
|
||||
dict/dict0crea.c, dict/dict0load.c, dict/dict0boot.c,
|
||||
include/dict0dict.h, include/trx0trx.h, dict/dict0dict.c,
|
||||
trx/trx0trx.c, include/ha_prototypes.h, handler/ha_innodb.cc:
|
||||
When creating an index in innodb_strict_mode, check that the
|
||||
maximum record size will never exceed the B-tree page size limit.
|
||||
For uncompressed tables, there should always be enough space for
|
||||
two records in an empty B-tree page. For compressed tables, there
|
||||
should be enough space for storing two node pointer records or one
|
||||
data record in an empty page in uncompressed format.
|
||||
The purpose of this check is to guarantee that INSERT or UPDATE
|
||||
will never fail due to too big record size.
|
||||
|
||||
2008-09-17 The InnoDB Team
|
||||
|
||||
* btr/btr0cur.c, data/data0data.c, include/page0zip.h,
|
||||
include/page0zip.ic, page/page0zip.c, mysql-test/innodb_bug36172.test:
|
||||
Prevent infinite B-tree page splits in compressed tables by
|
||||
ensuring that there will always be enough space for two node
|
||||
pointer records in an empty B-tree page. Also, require that at
|
||||
least one data record will fit in an empty compressed page. This
|
||||
will reduce the maximum size of records in compressed tables.
|
||||
|
||||
2008-09-09 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb.result:
|
||||
Fix the failing innodb test by merging changes that MySQL made to
|
||||
that file (r2646.12.1 in MySQL BZR repository)
|
||||
|
||||
2008-09-09 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
|
||||
mysql-test/innodb-autoinc.test:
|
||||
Fix Bug#38839 auto increment does not work properly with InnoDB after
|
||||
update
|
||||
|
||||
2008-09-09 The InnoDB Team
|
||||
|
||||
* dict/dict0dict.c, handler/handler0alter.cc, include/dict0dict.h,
|
||||
mysql-test/innodb-index.result, mysql-test/innodb-index.test:
|
||||
Fix Bug#38786 InnoDB plugin crashes on drop table/create table with FK
|
||||
|
||||
2008-08-21 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, include/ha_prototypes.h, row/row0sel.c:
|
||||
Fix Bug#37885 row_search_for_mysql may gap lock unnecessarily with SQL
|
||||
comments in query
|
||||
|
||||
2008-08-21 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Fix Bug#38185 ha_innobase::info can hold locks even when called with
|
||||
HA_STATUS_NO_LOCK
|
||||
|
||||
2008-08-18 The InnoDB Team
|
||||
|
||||
* buf/buf0buf.c, buf/buf0lru.c, include/buf0buf.ic, include/univ.i:
|
||||
Introduce UNIV_LRU_DEBUG for debugging the LRU buffer pool cache
|
||||
|
||||
2008-08-08 The InnoDB Team
|
||||
|
||||
* buf/buf0lru.c, include/buf0buf.h:
|
||||
Fix two recovery bugs that could lead to a crash in debug builds with
|
||||
small buffer size
|
||||
|
||||
2008-08-07 The InnoDB Team
|
||||
|
||||
* btr/btr0cur.c, handler/ha_innodb.cc, include/srv0srv.h,
|
||||
srv/srv0srv.c:
|
||||
Add a parameter innodb_stats_sample_pages to allow users to control
|
||||
the number of index dives when InnoDB estimates the cardinality of
|
||||
an index (ANALYZE TABLE, SHOW TABLE STATUS etc)
|
||||
|
||||
2008-08-07 The InnoDB Team
|
||||
|
||||
* trx/trx0i_s.c:
|
||||
Fix a bug that would lead to a crash if a SELECT was issued from the
|
||||
INFORMATION_SCHEMA tables and there are rolling back transactions at
|
||||
the same time
|
||||
|
||||
2008-08-06 The InnoDB Team
|
||||
|
||||
* btr/btr0btr.c, btr/btr0cur.c, ibuf/ibuf0ibuf.c, include/btr0cur.h,
|
||||
include/trx0roll.h, include/trx0types.h, row/row0purge.c,
|
||||
row/row0uins.c, row/row0umod.c, trx/trx0roll.c:
|
||||
In the rollback of incomplete transactions after crash recovery,
|
||||
tolerate clustered index records whose externally stored columns
|
||||
have not been written.
|
||||
|
||||
2008-07-30 The InnoDB Team
|
||||
|
||||
* trx/trx0trx.c:
|
||||
Fixes a race in recovery where the recovery thread recovering a
|
||||
PREPARED trx and the background rollback thread can both try
|
||||
to free the trx after its status is set to COMMITTED_IN_MEMORY.
|
||||
|
||||
2008-07-29 The InnoDB Team
|
||||
|
||||
* include/trx0rec.h, row/row0purge.c, row/row0vers.c, trx/trx0rec.c:
|
||||
Fix a BLOB corruption bug
|
||||
|
||||
2008-07-15 The InnoDB Team
|
||||
|
||||
* btr/btr0sea.c, dict/dict0dict.c, include/btr0sea.h:
|
||||
Fixed a timing hole where a thread dropping an index can free the
|
||||
in-memory index struct while another thread is still using that
|
||||
structure to remove entries from adaptive hash index belonging
|
||||
to one of the pages that belongs to the index being dropped.
|
||||
|
||||
2008-07-04 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb-index.result:
|
||||
Fix the failing innodb-index test by adjusting the result to a new
|
||||
MySQL behavior (the change occured in BZR-r2667)
|
||||
|
||||
2008-07-03 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb-zip.result, mysql-test/innodb-zip.test:
|
||||
Remove the negative test cases that produce warnings
|
||||
|
||||
2008-07-02 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb-replace.result, mysql-test/innodb-index.test:
|
||||
Disable part of innodb-index test because MySQL changed its behavior
|
||||
and is not calling ::add_index() anymore when adding primary index on
|
||||
non-NULL column
|
||||
|
||||
2008-07-01 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb-replace.result, mysql-test/innodb-replace.test:
|
||||
Fix the failing innodb-replace test by merging changes that MySQL
|
||||
made to that file (r2659 in MySQL BZR repository)
|
||||
|
||||
2008-07-01 The InnoDB Team
|
||||
|
||||
* lock/lock0lock.c:
|
||||
Fix Bug#36942 Performance problem in lock_get_n_rec_locks (SHOW INNODB
|
||||
STATUS)
|
||||
|
||||
2008-07-01 The InnoDB Team
|
||||
|
||||
* ha/ha0ha.c:
|
||||
Fix Bug#36941 Performance problem in ha_print_info (SHOW INNODB
|
||||
STATUS)
|
||||
|
||||
2008-07-01 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb-autoinc.result,
|
||||
mysql-test/innodb-autoinc.test:
|
||||
Fix Bug#37531 After truncate, auto_increment behaves incorrectly for
|
||||
InnoDB
|
||||
|
||||
2008-06-19 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Rewrite the function innodb_plugin_init() to support parameters in
|
||||
different order (in static and dynamic InnoDB) and to support more
|
||||
parameters in the static InnoDB
|
||||
|
||||
2008-06-19 The InnoDB Team
|
||||
|
||||
* handler/handler0alter.cc:
|
||||
Fix a bug in ::add_index() which set the transaction state to "active"
|
||||
but never restored it to the original value. This bug caused warnings
|
||||
to be printed by the rpl.rpl_ddl mysql-test.
|
||||
|
||||
2008-06-19 The InnoDB Team
|
||||
|
||||
* mysql-test/patches:
|
||||
Add a directory which contains patches, which need to be applied to
|
||||
MySQL source in order to get some mysql-tests to succeed. The patches
|
||||
cannot be committed in MySQL repository because they are specific to
|
||||
the InnoDB plugin.
|
||||
|
||||
2008-06-19 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb-zip.result, mysql-test/innodb-zip.test,
|
||||
row/row0row.c:
|
||||
Fix an anomaly when updating a record with BLOB prefix
|
||||
|
||||
2008-06-18 The InnoDB Team
|
||||
|
||||
* include/trx0sys.h, srv/srv0start.c, trx/trx0sys.c:
|
||||
Fix a bug in recovery which was a side effect of the file_format_check
|
||||
changes
|
||||
|
||||
2008-06-09 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb.result:
|
||||
Fix the failing innodb test by merging changes that MySQL made to that
|
||||
file
|
||||
|
||||
2008-06-06 The InnoDB Team
|
||||
|
||||
* buf/buf0buf.c, handler/ha_innodb.cc, include/buf0buf.h,
|
||||
include/srv0srv.h, srv/srv0srv.c:
|
||||
Fix Bug#36600 SHOW STATUS takes a lot of CPU in
|
||||
buf_get_latched_pages_number
|
||||
|
||||
* handler/ha_innodb.cc, os/os0file.c:
|
||||
Fix Bug#11894 innodb_file_per_table crashes w/ Windows .sym symbolic
|
||||
link hack
|
||||
|
||||
* include/ut0ut.h, srv/srv0srv.c, ut/ut0ut.c:
|
||||
Fix Bug#36819 ut_usectime does not handle errors from gettimeofday
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Fix Bug#35602 Failed to read auto-increment value from storage engine
|
||||
|
||||
* srv/srv0start.c:
|
||||
Fix Bug#36149 Read buffer overflow in srv0start.c found during "make
|
||||
test"
|
||||
|
||||
2008-05-08 The InnoDB Team
|
||||
|
||||
* btr/btr0btr.c, mysql-test/innodb_bug36172.result,
|
||||
mysql-test/innodb_bug36172.test:
|
||||
Fix Bug#36172 insert into compressed innodb table crashes
|
||||
|
||||
2008-05-08 The InnoDB Team
|
||||
|
||||
InnoDB Plugin 1.0.1 released
|
||||
|
||||
2008-05-06 The InnoDB Team
|
||||
|
||||
* handler/ha_innodb.cc, include/srv0srv.h, include/sync0sync.h,
|
||||
include/trx0sys.h, mysql-test/innodb-zip.result,
|
||||
mysql-test/innodb-zip.test, srv/srv0srv.c, srv/srv0start.c,
|
||||
sync/sync0sync.c, trx/trx0sys.c:
|
||||
Implement the system tablespace tagging
|
||||
|
||||
* handler/ha_innodb.cc, handler/i_s.cc, include/univ.i,
|
||||
srv/srv0start.c:
|
||||
Add InnoDB version in INFORMATION_SCHEMA.PLUGINS.PLUGIN_VERSION,
|
||||
in the startup message and in a server variable innodb_version.
|
||||
|
||||
* sync/sync0sync.c:
|
||||
Fix a bug in the sync debug code where a lock with level
|
||||
SYNC_LEVEL_VARYING would cause an assertion failure when a thread
|
||||
tried to release it.
|
||||
|
||||
2008-04-30 The InnoDB Team
|
||||
|
||||
* Makefile.am:
|
||||
Fix Bug#36434 ha_innodb.so is installed in the wrong directory
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Merge change from MySQL (Fix Bug#35406 5.1-opt crashes on select from
|
||||
I_S.REFERENTIAL_CONSTRAINTS):
|
||||
ChangeSet@1.2563, 2008-03-18 19:42:04+04:00, gluh@mysql.com +1 -0
|
||||
|
||||
* scripts/install_innodb_plugins.sql:
|
||||
Added
|
||||
|
||||
* mysql-test/innodb.result:
|
||||
Merge change from MySQL (this fixes the failing innodb test):
|
||||
ChangeSet@1.1810.3601.4, 2008-02-07 02:33:21+04:00
|
||||
|
||||
* row/row0sel.c:
|
||||
Fix Bug#35226 RBR event crashes slave
|
||||
|
||||
* handler/ha_innodb.cc:
|
||||
Change the fix for Bug#32440 to show bytes instead of kilobytes in
|
||||
INFORMATION_SCHEMA.TABLES.DATA_FREE
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb.result,
|
||||
mysql-test/innodb.test:
|
||||
Fix Bug#29507 TRUNCATE shows to many rows effected
|
||||
|
||||
* handler/ha_innodb.cc, mysql-test/innodb.result,
|
||||
mysql-test/innodb.test:
|
||||
Fix Bug#35537 Innodb doesn't increment handler_update and
|
||||
handler_delete
|
||||
|
||||
2008-04-29 The InnoDB Team
|
||||
|
||||
* handler/i_s.cc, include/srv0start.h, srv/srv0start.c:
|
||||
Fix Bug#36310 InnoDB plugin crash
|
||||
|
||||
2008-04-23 The InnoDB Team
|
||||
|
||||
* mysql-test/innodb_bug36169.result, mysql-test/innodb_bug36169.test,
|
||||
row/row0mysql.c:
|
||||
Fix Bug#36169 create innodb compressed table with too large row size
|
||||
crashed
|
||||
|
||||
* (outside the source tree):
|
||||
Fix Bug#36222 New InnoDB plugin 1.0 has wrong MKDIR_P defined in
|
||||
Makefile.in
|
||||
|
||||
2008-04-15 The InnoDB Team
|
||||
|
||||
InnoDB Plugin 1.0.0 released
|
||||
195
storage/xtradb/Makefile.am
Normal file
195
storage/xtradb/Makefile.am
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# Copyright (C) 2001, 2004, 2006 MySQL AB & Innobase Oy
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation; version 2 of the License.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
# Process this file with automake to create Makefile.in
|
||||
|
||||
MYSQLDATAdir= $(localstatedir)
|
||||
MYSQLSHAREdir= $(pkgdatadir)
|
||||
MYSQLBASEdir= $(prefix)
|
||||
MYSQLLIBdir= $(pkglibdir)
|
||||
pkgplugindir= $(pkglibdir)/plugin
|
||||
INCLUDES= -I$(top_srcdir)/include -I$(top_builddir)/include \
|
||||
-I$(top_srcdir)/regex \
|
||||
-I$(top_srcdir)/storage/xtradb/include \
|
||||
-I$(top_srcdir)/sql \
|
||||
-I$(srcdir)
|
||||
|
||||
DEFS= @DEFS@
|
||||
|
||||
|
||||
noinst_HEADERS= include/btr0btr.h include/btr0btr.ic \
|
||||
include/btr0cur.h include/btr0cur.ic \
|
||||
include/btr0pcur.h include/btr0pcur.ic \
|
||||
include/btr0sea.h include/btr0sea.ic \
|
||||
include/btr0types.h include/buf0buddy.h \
|
||||
include/buf0buddy.ic include/buf0buf.h \
|
||||
include/buf0buf.ic include/buf0flu.h \
|
||||
include/buf0flu.ic include/buf0lru.h \
|
||||
include/buf0lru.ic include/buf0rea.h \
|
||||
include/buf0types.h include/data0data.h \
|
||||
include/data0data.ic include/data0type.h \
|
||||
include/data0type.ic include/data0types.h \
|
||||
include/db0err.h include/dict0boot.h \
|
||||
include/dict0boot.ic include/dict0crea.h \
|
||||
include/dict0crea.ic include/dict0dict.h \
|
||||
include/dict0dict.ic include/dict0load.h \
|
||||
include/dict0load.ic include/dict0mem.h \
|
||||
include/dict0mem.ic include/dict0types.h \
|
||||
include/dyn0dyn.h include/dyn0dyn.ic \
|
||||
include/eval0eval.h include/eval0eval.ic \
|
||||
include/eval0proc.h include/eval0proc.ic \
|
||||
include/fil0fil.h include/fsp0fsp.h \
|
||||
include/fsp0fsp.ic include/fut0fut.h \
|
||||
include/fut0fut.ic include/fut0lst.h \
|
||||
include/fut0lst.ic include/ha0ha.h \
|
||||
include/ha0ha.ic \
|
||||
include/ha0storage.h \
|
||||
include/ha0storage.ic \
|
||||
include/hash0hash.h \
|
||||
include/hash0hash.ic include/ibuf0ibuf.h \
|
||||
include/ibuf0ibuf.ic include/ibuf0types.h \
|
||||
include/lock0iter.h \
|
||||
include/lock0lock.h include/lock0lock.ic \
|
||||
include/lock0priv.h include/lock0priv.ic \
|
||||
include/lock0types.h include/log0log.h \
|
||||
include/log0log.ic include/log0recv.h \
|
||||
include/log0recv.ic include/mach0data.h \
|
||||
include/mach0data.ic include/mem0dbg.h \
|
||||
include/mem0dbg.ic mem/mem0dbg.c \
|
||||
include/mem0mem.h include/mem0mem.ic \
|
||||
include/mem0pool.h include/mem0pool.ic \
|
||||
include/mtr0log.h include/mtr0log.ic \
|
||||
include/mtr0mtr.h include/mtr0mtr.ic \
|
||||
include/mtr0types.h \
|
||||
include/mysql_addons.h \
|
||||
include/os0file.h \
|
||||
include/os0proc.h include/os0proc.ic \
|
||||
include/os0sync.h include/os0sync.ic \
|
||||
include/os0thread.h include/os0thread.ic \
|
||||
include/page0cur.h include/page0cur.ic \
|
||||
include/page0page.h include/page0page.ic \
|
||||
include/page0zip.h include/page0zip.ic \
|
||||
include/page0types.h include/pars0grm.h \
|
||||
include/pars0opt.h include/pars0opt.ic \
|
||||
include/pars0pars.h include/pars0pars.ic \
|
||||
include/pars0sym.h include/pars0sym.ic \
|
||||
include/pars0types.h include/que0que.h \
|
||||
include/que0que.ic include/que0types.h \
|
||||
include/read0read.h include/read0read.ic \
|
||||
include/read0types.h include/rem0cmp.h \
|
||||
include/rem0cmp.ic include/rem0rec.h \
|
||||
include/rem0rec.ic include/rem0types.h \
|
||||
include/row0ext.h include/row0ext.ic \
|
||||
include/row0ins.h include/row0ins.ic \
|
||||
include/row0merge.h \
|
||||
include/row0mysql.h include/row0mysql.ic \
|
||||
include/row0purge.h include/row0purge.ic \
|
||||
include/row0row.h include/row0row.ic \
|
||||
include/row0sel.h include/row0sel.ic \
|
||||
include/row0types.h include/row0uins.h \
|
||||
include/row0uins.ic include/row0umod.h \
|
||||
include/row0umod.ic include/row0undo.h \
|
||||
include/row0undo.ic include/row0upd.h \
|
||||
include/row0upd.ic include/row0vers.h \
|
||||
include/row0vers.ic include/srv0que.h \
|
||||
include/srv0srv.h include/srv0srv.ic \
|
||||
include/srv0start.h include/sync0arr.h \
|
||||
include/sync0arr.ic include/sync0rw.h \
|
||||
include/sync0rw.ic include/sync0sync.h \
|
||||
include/sync0sync.ic include/sync0types.h \
|
||||
include/thr0loc.h include/thr0loc.ic \
|
||||
include/trx0i_s.h \
|
||||
include/trx0purge.h include/trx0purge.ic \
|
||||
include/trx0rec.h include/trx0rec.ic \
|
||||
include/trx0roll.h include/trx0roll.ic \
|
||||
include/trx0rseg.h include/trx0rseg.ic \
|
||||
include/trx0sys.h include/trx0sys.ic \
|
||||
include/trx0trx.h include/trx0trx.ic \
|
||||
include/trx0types.h include/trx0undo.h \
|
||||
include/trx0undo.ic include/trx0xa.h \
|
||||
include/univ.i include/usr0sess.h \
|
||||
include/usr0sess.ic include/usr0types.h \
|
||||
include/ut0byte.h include/ut0byte.ic \
|
||||
include/ut0dbg.h include/ut0lst.h \
|
||||
include/ut0mem.h include/ut0mem.ic \
|
||||
include/ut0rnd.h include/ut0rnd.ic \
|
||||
include/ut0sort.h include/ut0ut.h \
|
||||
include/ut0ut.ic include/ut0vec.h \
|
||||
include/ut0vec.ic include/ut0list.h \
|
||||
include/ut0list.ic include/ut0wqueue.h \
|
||||
include/ha_prototypes.h handler/ha_innodb.h \
|
||||
include/handler0alter.h \
|
||||
handler/i_s.h handler/innodb_patch_info.h
|
||||
|
||||
EXTRA_LIBRARIES= libinnobase.a
|
||||
noinst_LIBRARIES= @plugin_innobase_static_target@
|
||||
libinnobase_a_SOURCES= btr/btr0btr.c btr/btr0cur.c btr/btr0pcur.c \
|
||||
btr/btr0sea.c buf/buf0buddy.c \
|
||||
buf/buf0buf.c buf/buf0flu.c \
|
||||
buf/buf0lru.c buf/buf0rea.c data/data0data.c \
|
||||
data/data0type.c dict/dict0boot.c \
|
||||
dict/dict0crea.c dict/dict0dict.c \
|
||||
dict/dict0load.c dict/dict0mem.c dyn/dyn0dyn.c \
|
||||
eval/eval0eval.c eval/eval0proc.c \
|
||||
fil/fil0fil.c fsp/fsp0fsp.c fut/fut0fut.c \
|
||||
fut/fut0lst.c ha/ha0ha.c \
|
||||
ha/ha0storage.c \
|
||||
ha/hash0hash.c \
|
||||
ibuf/ibuf0ibuf.c lock/lock0iter.c \
|
||||
lock/lock0lock.c \
|
||||
log/log0log.c log/log0recv.c mach/mach0data.c \
|
||||
mem/mem0mem.c mem/mem0pool.c mtr/mtr0log.c \
|
||||
mtr/mtr0mtr.c os/os0file.c os/os0proc.c \
|
||||
os/os0sync.c os/os0thread.c page/page0cur.c \
|
||||
page/page0page.c page/page0zip.c \
|
||||
pars/lexyy.c pars/pars0grm.c \
|
||||
pars/pars0opt.c pars/pars0pars.c \
|
||||
pars/pars0sym.c que/que0que.c read/read0read.c \
|
||||
rem/rem0cmp.c rem/rem0rec.c row/row0ext.c \
|
||||
row/row0ins.c row/row0merge.c \
|
||||
row/row0mysql.c row/row0purge.c row/row0row.c \
|
||||
row/row0sel.c row/row0uins.c row/row0umod.c \
|
||||
row/row0undo.c row/row0upd.c row/row0vers.c \
|
||||
srv/srv0que.c srv/srv0srv.c srv/srv0start.c \
|
||||
sync/sync0arr.c sync/sync0rw.c \
|
||||
sync/sync0sync.c thr/thr0loc.c \
|
||||
trx/trx0i_s.c \
|
||||
trx/trx0purge.c \
|
||||
trx/trx0rec.c trx/trx0roll.c trx/trx0rseg.c \
|
||||
trx/trx0sys.c trx/trx0trx.c trx/trx0undo.c \
|
||||
usr/usr0sess.c ut/ut0byte.c ut/ut0dbg.c \
|
||||
ut/ut0list.c ut/ut0mem.c ut/ut0rnd.c \
|
||||
ut/ut0ut.c ut/ut0vec.c ut/ut0wqueue.c \
|
||||
handler/ha_innodb.cc handler/handler0alter.cc \
|
||||
handler/i_s.cc \
|
||||
handler/mysql_addons.cc
|
||||
|
||||
libinnobase_a_CXXFLAGS= $(AM_CFLAGS)
|
||||
libinnobase_a_CFLAGS= $(AM_CFLAGS)
|
||||
|
||||
EXTRA_LTLIBRARIES= ha_innodb.la
|
||||
pkgplugin_LTLIBRARIES= @plugin_innobase_shared_target@
|
||||
|
||||
ha_innodb_la_LDFLAGS= -module -rpath $(pkgplugindir)
|
||||
ha_innodb_la_CXXFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
|
||||
ha_innodb_la_CFLAGS= $(AM_CFLAGS) $(INNODB_DYNAMIC_CFLAGS)
|
||||
ha_innodb_la_SOURCES= $(libinnobase_a_SOURCES)
|
||||
|
||||
EXTRA_DIST= CMakeLists.txt plug.in \
|
||||
pars/make_bison.sh pars/make_flex.sh \
|
||||
pars/pars0grm.y pars/pars0lex.l
|
||||
|
||||
# Don't update the files from bitkeeper
|
||||
%::SCCS/s.%
|
||||
3656
storage/xtradb/btr/btr0btr.c
Normal file
3656
storage/xtradb/btr/btr0btr.c
Normal file
File diff suppressed because it is too large
Load diff
4848
storage/xtradb/btr/btr0cur.c
Normal file
4848
storage/xtradb/btr/btr0cur.c
Normal file
File diff suppressed because it is too large
Load diff
584
storage/xtradb/btr/btr0pcur.c
Normal file
584
storage/xtradb/btr/btr0pcur.c
Normal file
|
|
@ -0,0 +1,584 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
The index tree persistent cursor
|
||||
|
||||
Created 2/23/1996 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "btr0pcur.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "btr0pcur.ic"
|
||||
#endif
|
||||
|
||||
#include "ut0byte.h"
|
||||
#include "rem0cmp.h"
|
||||
#include "trx0trx.h"
|
||||
|
||||
/******************************************************************
|
||||
Allocates memory for a persistent cursor object and initializes the cursor. */
|
||||
UNIV_INTERN
|
||||
btr_pcur_t*
|
||||
btr_pcur_create_for_mysql(void)
|
||||
/*============================*/
|
||||
/* out, own: persistent cursor */
|
||||
{
|
||||
btr_pcur_t* pcur;
|
||||
|
||||
pcur = mem_alloc(sizeof(btr_pcur_t));
|
||||
|
||||
pcur->btr_cur.index = NULL;
|
||||
btr_pcur_init(pcur);
|
||||
|
||||
return(pcur);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
Frees the memory for a persistent cursor object. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_pcur_free_for_mysql(
|
||||
/*====================*/
|
||||
btr_pcur_t* cursor) /* in, own: persistent cursor */
|
||||
{
|
||||
if (cursor->old_rec_buf != NULL) {
|
||||
|
||||
mem_free(cursor->old_rec_buf);
|
||||
|
||||
cursor->old_rec_buf = NULL;
|
||||
}
|
||||
|
||||
cursor->btr_cur.page_cur.rec = NULL;
|
||||
cursor->old_rec = NULL;
|
||||
cursor->old_n_fields = 0;
|
||||
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
|
||||
|
||||
cursor->latch_mode = BTR_NO_LATCHES;
|
||||
cursor->pos_state = BTR_PCUR_NOT_POSITIONED;
|
||||
|
||||
mem_free(cursor);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
The position of the cursor is stored by taking an initial segment of the
|
||||
record the cursor is positioned on, before, or after, and copying it to the
|
||||
cursor data structure, or just setting a flag if the cursor id before the
|
||||
first in an EMPTY tree, or after the last in an EMPTY tree. NOTE that the
|
||||
page where the cursor is positioned must not be empty if the index tree is
|
||||
not totally empty! */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_pcur_store_position(
|
||||
/*====================*/
|
||||
btr_pcur_t* cursor, /* in: persistent cursor */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
page_cur_t* page_cursor;
|
||||
buf_block_t* block;
|
||||
rec_t* rec;
|
||||
dict_index_t* index;
|
||||
page_t* page;
|
||||
ulint offs;
|
||||
|
||||
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
block = btr_pcur_get_block(cursor);
|
||||
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
|
||||
|
||||
page_cursor = btr_pcur_get_page_cur(cursor);
|
||||
|
||||
rec = page_cur_get_rec(page_cursor);
|
||||
page = page_align(rec);
|
||||
offs = page_offset(rec);
|
||||
|
||||
ut_ad(mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_S_FIX)
|
||||
|| mtr_memo_contains(mtr, block, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_a(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
if (UNIV_UNLIKELY(page_get_n_recs(page) == 0)) {
|
||||
/* It must be an empty index tree; NOTE that in this case
|
||||
we do not store the modify_clock, but always do a search
|
||||
if we restore the cursor position */
|
||||
|
||||
ut_a(btr_page_get_next(page, mtr) == FIL_NULL);
|
||||
ut_a(btr_page_get_prev(page, mtr) == FIL_NULL);
|
||||
|
||||
cursor->old_stored = BTR_PCUR_OLD_STORED;
|
||||
|
||||
if (page_rec_is_supremum_low(offs)) {
|
||||
|
||||
cursor->rel_pos = BTR_PCUR_AFTER_LAST_IN_TREE;
|
||||
} else {
|
||||
cursor->rel_pos = BTR_PCUR_BEFORE_FIRST_IN_TREE;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (page_rec_is_supremum_low(offs)) {
|
||||
|
||||
rec = page_rec_get_prev(rec);
|
||||
|
||||
cursor->rel_pos = BTR_PCUR_AFTER;
|
||||
|
||||
} else if (page_rec_is_infimum_low(offs)) {
|
||||
|
||||
rec = page_rec_get_next(rec);
|
||||
|
||||
cursor->rel_pos = BTR_PCUR_BEFORE;
|
||||
} else {
|
||||
cursor->rel_pos = BTR_PCUR_ON;
|
||||
}
|
||||
|
||||
cursor->old_stored = BTR_PCUR_OLD_STORED;
|
||||
cursor->old_rec = dict_index_copy_rec_order_prefix(
|
||||
index, rec, &cursor->old_n_fields,
|
||||
&cursor->old_rec_buf, &cursor->buf_size);
|
||||
|
||||
cursor->block_when_stored = block;
|
||||
cursor->modify_clock = buf_block_get_modify_clock(block);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
Copies the stored position of a pcur to another pcur. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_pcur_copy_stored_position(
|
||||
/*==========================*/
|
||||
btr_pcur_t* pcur_receive, /* in: pcur which will receive the
|
||||
position info */
|
||||
btr_pcur_t* pcur_donate) /* in: pcur from which the info is
|
||||
copied */
|
||||
{
|
||||
if (pcur_receive->old_rec_buf) {
|
||||
mem_free(pcur_receive->old_rec_buf);
|
||||
}
|
||||
|
||||
ut_memcpy(pcur_receive, pcur_donate, sizeof(btr_pcur_t));
|
||||
|
||||
if (pcur_donate->old_rec_buf) {
|
||||
|
||||
pcur_receive->old_rec_buf = mem_alloc(pcur_donate->buf_size);
|
||||
|
||||
ut_memcpy(pcur_receive->old_rec_buf, pcur_donate->old_rec_buf,
|
||||
pcur_donate->buf_size);
|
||||
pcur_receive->old_rec = pcur_receive->old_rec_buf
|
||||
+ (pcur_donate->old_rec - pcur_donate->old_rec_buf);
|
||||
}
|
||||
|
||||
pcur_receive->old_n_fields = pcur_donate->old_n_fields;
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
Restores the stored position of a persistent cursor bufferfixing the page and
|
||||
obtaining the specified latches. If the cursor position was saved when the
|
||||
(1) cursor was positioned on a user record: this function restores the position
|
||||
to the last record LESS OR EQUAL to the stored record;
|
||||
(2) cursor was positioned on a page infimum record: restores the position to
|
||||
the last record LESS than the user record which was the successor of the page
|
||||
infimum;
|
||||
(3) cursor was positioned on the page supremum: restores to the first record
|
||||
GREATER than the user record which was the predecessor of the supremum.
|
||||
(4) cursor was positioned before the first or after the last in an empty tree:
|
||||
restores to before first or after the last in the tree. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
btr_pcur_restore_position(
|
||||
/*======================*/
|
||||
/* out: TRUE if the cursor position
|
||||
was stored when it was on a user record
|
||||
and it can be restored on a user record
|
||||
whose ordering fields are identical to
|
||||
the ones of the original user record */
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF, ... */
|
||||
btr_pcur_t* cursor, /* in: detached persistent cursor */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
dict_index_t* index;
|
||||
dtuple_t* tuple;
|
||||
ulint mode;
|
||||
ulint old_mode;
|
||||
mem_heap_t* heap;
|
||||
|
||||
index = btr_cur_get_index(btr_pcur_get_btr_cur(cursor));
|
||||
|
||||
if (UNIV_UNLIKELY(cursor->old_stored != BTR_PCUR_OLD_STORED)
|
||||
|| UNIV_UNLIKELY(cursor->pos_state != BTR_PCUR_WAS_POSITIONED
|
||||
&& cursor->pos_state != BTR_PCUR_IS_POSITIONED)) {
|
||||
ut_print_buf(stderr, cursor, sizeof(btr_pcur_t));
|
||||
putc('\n', stderr);
|
||||
if (cursor->trx_if_known) {
|
||||
trx_print(stderr, cursor->trx_if_known, 0);
|
||||
}
|
||||
|
||||
ut_error;
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY
|
||||
(cursor->rel_pos == BTR_PCUR_AFTER_LAST_IN_TREE
|
||||
|| cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE)) {
|
||||
|
||||
/* In these cases we do not try an optimistic restoration,
|
||||
but always do a search */
|
||||
|
||||
btr_cur_open_at_index_side(
|
||||
cursor->rel_pos == BTR_PCUR_BEFORE_FIRST_IN_TREE,
|
||||
index, latch_mode, btr_pcur_get_btr_cur(cursor), mtr);
|
||||
|
||||
cursor->block_when_stored = btr_pcur_get_block(cursor);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
ut_a(cursor->old_rec);
|
||||
ut_a(cursor->old_n_fields);
|
||||
|
||||
if (UNIV_LIKELY(latch_mode == BTR_SEARCH_LEAF)
|
||||
|| UNIV_LIKELY(latch_mode == BTR_MODIFY_LEAF)) {
|
||||
/* Try optimistic restoration */
|
||||
|
||||
if (UNIV_LIKELY(buf_page_optimistic_get(
|
||||
latch_mode,
|
||||
cursor->block_when_stored,
|
||||
cursor->modify_clock, mtr))) {
|
||||
cursor->pos_state = BTR_PCUR_IS_POSITIONED;
|
||||
|
||||
buf_block_dbg_add_level(btr_pcur_get_block(cursor),
|
||||
SYNC_TREE_NODE);
|
||||
|
||||
if (cursor->rel_pos == BTR_PCUR_ON) {
|
||||
#ifdef UNIV_DEBUG
|
||||
const rec_t* rec;
|
||||
const ulint* offsets1;
|
||||
const ulint* offsets2;
|
||||
#endif /* UNIV_DEBUG */
|
||||
cursor->latch_mode = latch_mode;
|
||||
#ifdef UNIV_DEBUG
|
||||
rec = btr_pcur_get_rec(cursor);
|
||||
|
||||
heap = mem_heap_create(256);
|
||||
offsets1 = rec_get_offsets(
|
||||
cursor->old_rec, index, NULL,
|
||||
cursor->old_n_fields, &heap);
|
||||
offsets2 = rec_get_offsets(
|
||||
rec, index, NULL,
|
||||
cursor->old_n_fields, &heap);
|
||||
|
||||
ut_ad(!cmp_rec_rec(cursor->old_rec,
|
||||
rec, offsets1, offsets2,
|
||||
index));
|
||||
mem_heap_free(heap);
|
||||
#endif /* UNIV_DEBUG */
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* If optimistic restoration did not succeed, open the cursor anew */
|
||||
|
||||
heap = mem_heap_create(256);
|
||||
|
||||
tuple = dict_index_build_data_tuple(index, cursor->old_rec,
|
||||
cursor->old_n_fields, heap);
|
||||
|
||||
/* Save the old search mode of the cursor */
|
||||
old_mode = cursor->search_mode;
|
||||
|
||||
if (UNIV_LIKELY(cursor->rel_pos == BTR_PCUR_ON)) {
|
||||
mode = PAGE_CUR_LE;
|
||||
} else if (cursor->rel_pos == BTR_PCUR_AFTER) {
|
||||
mode = PAGE_CUR_G;
|
||||
} else {
|
||||
ut_ad(cursor->rel_pos == BTR_PCUR_BEFORE);
|
||||
mode = PAGE_CUR_L;
|
||||
}
|
||||
|
||||
btr_pcur_open_with_no_init(index, tuple, mode, latch_mode,
|
||||
cursor, 0, mtr);
|
||||
|
||||
/* 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))) {
|
||||
|
||||
/* 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;
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
/* We have to store new position information, modify_clock etc.,
|
||||
to the cursor because it can now be on a different page, the record
|
||||
under it may have been removed, etc. */
|
||||
|
||||
btr_pcur_store_position(cursor, mtr);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
If the latch mode of the cursor is BTR_LEAF_SEARCH or BTR_LEAF_MODIFY,
|
||||
releases the page latch and bufferfix reserved by the cursor.
|
||||
NOTE! In the case of BTR_LEAF_MODIFY, there should not exist changes
|
||||
made by the current mini-transaction to the data protected by the
|
||||
cursor latch, as then the latch must not be released until mtr_commit. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_pcur_release_leaf(
|
||||
/*==================*/
|
||||
btr_pcur_t* cursor, /* in: persistent cursor */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
buf_block_t* block;
|
||||
|
||||
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
block = btr_pcur_get_block(cursor);
|
||||
|
||||
btr_leaf_page_release(block, cursor->latch_mode, mtr);
|
||||
|
||||
cursor->latch_mode = BTR_NO_LATCHES;
|
||||
|
||||
cursor->pos_state = BTR_PCUR_WAS_POSITIONED;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Moves the persistent cursor to the first record on the next page. Releases the
|
||||
latch on the current page, and bufferunfixes it. Note that there must not be
|
||||
modifications on the current page, as then the x-latch can be released only in
|
||||
mtr_commit. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_pcur_move_to_next_page(
|
||||
/*=======================*/
|
||||
btr_pcur_t* cursor, /* in: persistent cursor; must be on the
|
||||
last record of the current page */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ulint next_page_no;
|
||||
ulint space;
|
||||
ulint zip_size;
|
||||
page_t* page;
|
||||
buf_block_t* next_block;
|
||||
page_t* next_page;
|
||||
|
||||
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
ut_ad(btr_pcur_is_after_last_on_page(cursor));
|
||||
|
||||
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
|
||||
|
||||
page = btr_pcur_get_page(cursor);
|
||||
next_page_no = btr_page_get_next(page, mtr);
|
||||
space = buf_block_get_space(btr_pcur_get_block(cursor));
|
||||
zip_size = buf_block_get_zip_size(btr_pcur_get_block(cursor));
|
||||
|
||||
ut_ad(next_page_no != FIL_NULL);
|
||||
|
||||
next_block = btr_block_get(space, zip_size, next_page_no,
|
||||
cursor->latch_mode, mtr);
|
||||
next_page = buf_block_get_frame(next_block);
|
||||
#ifdef UNIV_BTR_DEBUG
|
||||
ut_a(page_is_comp(next_page) == page_is_comp(page));
|
||||
ut_a(btr_page_get_prev(next_page, mtr)
|
||||
== buf_block_get_page_no(btr_pcur_get_block(cursor)));
|
||||
#endif /* UNIV_BTR_DEBUG */
|
||||
next_block->check_index_page_at_flush = TRUE;
|
||||
|
||||
btr_leaf_page_release(btr_pcur_get_block(cursor),
|
||||
cursor->latch_mode, mtr);
|
||||
|
||||
page_cur_set_before_first(next_block, btr_pcur_get_page_cur(cursor));
|
||||
|
||||
page_check_dir(next_page);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Moves the persistent cursor backward if it is on the first record of the page.
|
||||
Commits mtr. Note that to prevent a possible deadlock, the operation
|
||||
first stores the position of the cursor, commits mtr, acquires the necessary
|
||||
latches and restores the cursor position again before returning. The
|
||||
alphabetical position of the cursor is guaranteed to be sensible on
|
||||
return, but it may happen that the cursor is not positioned on the last
|
||||
record of any page, because the structure of the tree may have changed
|
||||
during the time when the cursor had no latches. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_pcur_move_backward_from_page(
|
||||
/*=============================*/
|
||||
btr_pcur_t* cursor, /* in: persistent cursor, must be on the first
|
||||
record of the current page */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ulint prev_page_no;
|
||||
ulint space;
|
||||
page_t* page;
|
||||
buf_block_t* prev_block;
|
||||
ulint latch_mode;
|
||||
ulint latch_mode2;
|
||||
|
||||
ut_a(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
ut_ad(btr_pcur_is_before_first_on_page(cursor));
|
||||
ut_ad(!btr_pcur_is_before_first_in_tree(cursor, mtr));
|
||||
|
||||
latch_mode = cursor->latch_mode;
|
||||
|
||||
if (latch_mode == BTR_SEARCH_LEAF) {
|
||||
|
||||
latch_mode2 = BTR_SEARCH_PREV;
|
||||
|
||||
} else if (latch_mode == BTR_MODIFY_LEAF) {
|
||||
|
||||
latch_mode2 = BTR_MODIFY_PREV;
|
||||
} else {
|
||||
latch_mode2 = 0; /* To eliminate compiler warning */
|
||||
ut_error;
|
||||
}
|
||||
|
||||
btr_pcur_store_position(cursor, mtr);
|
||||
|
||||
mtr_commit(mtr);
|
||||
|
||||
mtr_start(mtr);
|
||||
|
||||
btr_pcur_restore_position(latch_mode2, cursor, mtr);
|
||||
|
||||
page = btr_pcur_get_page(cursor);
|
||||
|
||||
prev_page_no = btr_page_get_prev(page, mtr);
|
||||
space = buf_block_get_space(btr_pcur_get_block(cursor));
|
||||
|
||||
if (prev_page_no == FIL_NULL) {
|
||||
} else if (btr_pcur_is_before_first_on_page(cursor)) {
|
||||
|
||||
prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
|
||||
|
||||
btr_leaf_page_release(btr_pcur_get_block(cursor),
|
||||
latch_mode, mtr);
|
||||
|
||||
page_cur_set_after_last(prev_block,
|
||||
btr_pcur_get_page_cur(cursor));
|
||||
} else {
|
||||
|
||||
/* The repositioned cursor did not end on an infimum record on
|
||||
a page. Cursor repositioning acquired a latch also on the
|
||||
previous page, but we do not need the latch: release it. */
|
||||
|
||||
prev_block = btr_pcur_get_btr_cur(cursor)->left_block;
|
||||
|
||||
btr_leaf_page_release(prev_block, latch_mode, mtr);
|
||||
}
|
||||
|
||||
cursor->latch_mode = latch_mode;
|
||||
|
||||
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Moves the persistent cursor to the previous record in the tree. If no records
|
||||
are left, the cursor stays 'before first in tree'. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
btr_pcur_move_to_prev(
|
||||
/*==================*/
|
||||
/* out: TRUE if the cursor was not before first
|
||||
in tree */
|
||||
btr_pcur_t* cursor, /* in: persistent cursor; NOTE that the
|
||||
function may release the page latch */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
ut_ad(cursor->pos_state == BTR_PCUR_IS_POSITIONED);
|
||||
ut_ad(cursor->latch_mode != BTR_NO_LATCHES);
|
||||
|
||||
cursor->old_stored = BTR_PCUR_OLD_NOT_STORED;
|
||||
|
||||
if (btr_pcur_is_before_first_on_page(cursor)) {
|
||||
|
||||
if (btr_pcur_is_before_first_in_tree(cursor, mtr)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
btr_pcur_move_backward_from_page(cursor, mtr);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
btr_pcur_move_to_prev_on_page(cursor);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
If mode is PAGE_CUR_G or PAGE_CUR_GE, opens a persistent cursor on the first
|
||||
user record satisfying the search condition, in the case PAGE_CUR_L or
|
||||
PAGE_CUR_LE, on the last user record. If no such user record exists, then
|
||||
in the first case sets the cursor after last in tree, and in the latter case
|
||||
before first in tree. The latching mode must be BTR_SEARCH_LEAF or
|
||||
BTR_MODIFY_LEAF. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
btr_pcur_open_on_user_rec(
|
||||
/*======================*/
|
||||
dict_index_t* index, /* in: index */
|
||||
const dtuple_t* tuple, /* in: tuple on which search done */
|
||||
ulint mode, /* in: PAGE_CUR_L, ... */
|
||||
ulint latch_mode, /* in: BTR_SEARCH_LEAF or
|
||||
BTR_MODIFY_LEAF */
|
||||
btr_pcur_t* cursor, /* in: memory buffer for persistent
|
||||
cursor */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
btr_pcur_open(index, tuple, mode, latch_mode, cursor, mtr);
|
||||
|
||||
if ((mode == PAGE_CUR_GE) || (mode == PAGE_CUR_G)) {
|
||||
|
||||
if (btr_pcur_is_after_last_on_page(cursor)) {
|
||||
|
||||
btr_pcur_move_to_next_user_rec(cursor, mtr);
|
||||
}
|
||||
} else {
|
||||
ut_ad((mode == PAGE_CUR_LE) || (mode == PAGE_CUR_L));
|
||||
|
||||
/* Not implemented yet */
|
||||
|
||||
ut_error;
|
||||
}
|
||||
}
|
||||
1878
storage/xtradb/btr/btr0sea.c
Normal file
1878
storage/xtradb/btr/btr0sea.c
Normal file
File diff suppressed because it is too large
Load diff
785
storage/xtradb/buf/buf0buddy.c
Normal file
785
storage/xtradb/buf/buf0buddy.c
Normal file
|
|
@ -0,0 +1,785 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2006, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
Binary buddy allocator for compressed pages
|
||||
|
||||
Created December 2006 by Marko Makela
|
||||
*******************************************************/
|
||||
|
||||
#define THIS_MODULE
|
||||
#include "buf0buddy.h"
|
||||
#ifdef UNIV_NONINL
|
||||
# include "buf0buddy.ic"
|
||||
#endif
|
||||
#undef THIS_MODULE
|
||||
#include "buf0buf.h"
|
||||
#include "buf0lru.h"
|
||||
#include "buf0flu.h"
|
||||
#include "page0zip.h"
|
||||
|
||||
/* Statistic counters */
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/** Number of frames allocated from the buffer pool to the buddy system.
|
||||
Protected by buf_pool_mutex. */
|
||||
static ulint buf_buddy_n_frames;
|
||||
#endif /* UNIV_DEBUG */
|
||||
/** Statistics of the buddy system, indexed by block size.
|
||||
Protected by buf_pool_mutex. */
|
||||
UNIV_INTERN buf_buddy_stat_t buf_buddy_stat[BUF_BUDDY_SIZES + 1];
|
||||
|
||||
/**************************************************************************
|
||||
Get the offset of the buddy of a compressed page frame. */
|
||||
UNIV_INLINE
|
||||
byte*
|
||||
buf_buddy_get(
|
||||
/*==========*/
|
||||
/* out: the buddy relative of page */
|
||||
byte* page, /* in: compressed page */
|
||||
ulint size) /* in: page size in bytes */
|
||||
{
|
||||
ut_ad(ut_is_2pow(size));
|
||||
ut_ad(size >= BUF_BUDDY_LOW);
|
||||
ut_ad(size < BUF_BUDDY_HIGH);
|
||||
ut_ad(!ut_align_offset(page, size));
|
||||
|
||||
if (((ulint) page) & size) {
|
||||
return(page - size);
|
||||
} else {
|
||||
return(page + size);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Add a block to the head of the appropriate buddy free list. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_buddy_add_to_free(
|
||||
/*==================*/
|
||||
buf_page_t* bpage, /* in,own: block to be freed */
|
||||
ulint i) /* in: index of buf_pool->zip_free[] */
|
||||
{
|
||||
#ifdef UNIV_DEBUG_VALGRIND
|
||||
buf_page_t* b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
|
||||
if (b) UNIV_MEM_VALID(b, BUF_BUDDY_LOW << i);
|
||||
#endif /* UNIV_DEBUG_VALGRIND */
|
||||
|
||||
ut_ad(buf_pool->zip_free[i].start != bpage);
|
||||
UT_LIST_ADD_FIRST(zip_list, buf_pool->zip_free[i], bpage);
|
||||
|
||||
#ifdef UNIV_DEBUG_VALGRIND
|
||||
if (b) UNIV_MEM_FREE(b, BUF_BUDDY_LOW << i);
|
||||
UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i);
|
||||
#endif /* UNIV_DEBUG_VALGRIND */
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Remove a block from the appropriate buddy free list. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
buf_buddy_remove_from_free(
|
||||
/*=======================*/
|
||||
buf_page_t* bpage, /* in: block to be removed */
|
||||
ulint i) /* in: index of buf_pool->zip_free[] */
|
||||
{
|
||||
#ifdef UNIV_DEBUG_VALGRIND
|
||||
buf_page_t* prev = UT_LIST_GET_PREV(zip_list, bpage);
|
||||
buf_page_t* next = UT_LIST_GET_NEXT(zip_list, bpage);
|
||||
|
||||
if (prev) UNIV_MEM_VALID(prev, BUF_BUDDY_LOW << i);
|
||||
if (next) UNIV_MEM_VALID(next, BUF_BUDDY_LOW << i);
|
||||
|
||||
ut_ad(!prev || buf_page_get_state(prev) == BUF_BLOCK_ZIP_FREE);
|
||||
ut_ad(!next || buf_page_get_state(next) == BUF_BLOCK_ZIP_FREE);
|
||||
#endif /* UNIV_DEBUG_VALGRIND */
|
||||
|
||||
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
|
||||
UT_LIST_REMOVE(zip_list, buf_pool->zip_free[i], bpage);
|
||||
|
||||
#ifdef UNIV_DEBUG_VALGRIND
|
||||
if (prev) UNIV_MEM_FREE(prev, BUF_BUDDY_LOW << i);
|
||||
if (next) UNIV_MEM_FREE(next, BUF_BUDDY_LOW << i);
|
||||
#endif /* UNIV_DEBUG_VALGRIND */
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Try to allocate a block from buf_pool->zip_free[]. */
|
||||
static
|
||||
void*
|
||||
buf_buddy_alloc_zip(
|
||||
/*================*/
|
||||
/* out: allocated block, or NULL
|
||||
if buf_pool->zip_free[] was empty */
|
||||
ulint i) /* in: index of buf_pool->zip_free[] */
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
|
||||
//ut_ad(buf_pool_mutex_own());
|
||||
ut_ad(mutex_own(&zip_free_mutex));
|
||||
ut_a(i < BUF_BUDDY_SIZES);
|
||||
|
||||
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
|
||||
/* Valgrind would complain about accessing free memory. */
|
||||
UT_LIST_VALIDATE(zip_list, buf_page_t, buf_pool->zip_free[i]);
|
||||
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
|
||||
bpage = UT_LIST_GET_LAST(buf_pool->zip_free[i]);
|
||||
|
||||
if (bpage) {
|
||||
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
|
||||
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
|
||||
|
||||
buf_buddy_remove_from_free(bpage, i);
|
||||
} else if (i + 1 < BUF_BUDDY_SIZES) {
|
||||
/* Attempt to split. */
|
||||
bpage = buf_buddy_alloc_zip(i + 1);
|
||||
|
||||
if (bpage) {
|
||||
buf_page_t* buddy = (buf_page_t*)
|
||||
(((char*) bpage) + (BUF_BUDDY_LOW << i));
|
||||
|
||||
ut_ad(!buf_pool_contains_zip(buddy));
|
||||
ut_d(memset(buddy, i, BUF_BUDDY_LOW << i));
|
||||
buddy->state = BUF_BLOCK_ZIP_FREE;
|
||||
buf_buddy_add_to_free(buddy, i);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
if (bpage) {
|
||||
memset(bpage, ~i, BUF_BUDDY_LOW << i);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
UNIV_MEM_ALLOC(bpage, BUF_BUDDY_SIZES << i);
|
||||
|
||||
return(bpage);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Deallocate a buffer frame of UNIV_PAGE_SIZE. */
|
||||
static
|
||||
void
|
||||
buf_buddy_block_free(
|
||||
/*=================*/
|
||||
void* buf, /* in: buffer frame to deallocate */
|
||||
ibool have_page_hash_mutex)
|
||||
{
|
||||
const ulint fold = BUF_POOL_ZIP_FOLD_PTR(buf);
|
||||
buf_page_t* bpage;
|
||||
buf_block_t* block;
|
||||
|
||||
//ut_ad(buf_pool_mutex_own());
|
||||
ut_ad(!mutex_own(&buf_pool_zip_mutex));
|
||||
ut_a(!ut_align_offset(buf, UNIV_PAGE_SIZE));
|
||||
|
||||
mutex_enter(&zip_hash_mutex);
|
||||
|
||||
HASH_SEARCH(hash, buf_pool->zip_hash, fold, buf_page_t*, bpage,
|
||||
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_MEMORY
|
||||
&& bpage->in_zip_hash && !bpage->in_page_hash),
|
||||
((buf_block_t*) bpage)->frame == buf);
|
||||
ut_a(bpage);
|
||||
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_MEMORY);
|
||||
ut_ad(!bpage->in_page_hash);
|
||||
ut_ad(bpage->in_zip_hash);
|
||||
ut_d(bpage->in_zip_hash = FALSE);
|
||||
HASH_DELETE(buf_page_t, hash, buf_pool->zip_hash, fold, bpage);
|
||||
|
||||
mutex_exit(&zip_hash_mutex);
|
||||
|
||||
ut_d(memset(buf, 0, UNIV_PAGE_SIZE));
|
||||
UNIV_MEM_INVALID(buf, UNIV_PAGE_SIZE);
|
||||
|
||||
block = (buf_block_t*) bpage;
|
||||
mutex_enter(&block->mutex);
|
||||
buf_LRU_block_free_non_file_page(block, have_page_hash_mutex);
|
||||
mutex_exit(&block->mutex);
|
||||
|
||||
ut_ad(buf_buddy_n_frames > 0);
|
||||
ut_d(buf_buddy_n_frames--);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Allocate a buffer block to the buddy allocator. */
|
||||
static
|
||||
void
|
||||
buf_buddy_block_register(
|
||||
/*=====================*/
|
||||
buf_block_t* block) /* in: buffer frame to allocate */
|
||||
{
|
||||
const ulint fold = BUF_POOL_ZIP_FOLD(block);
|
||||
//ut_ad(buf_pool_mutex_own());
|
||||
ut_ad(!mutex_own(&buf_pool_zip_mutex));
|
||||
|
||||
buf_block_set_state(block, BUF_BLOCK_MEMORY);
|
||||
|
||||
ut_a(block->frame);
|
||||
ut_a(!ut_align_offset(block->frame, UNIV_PAGE_SIZE));
|
||||
|
||||
ut_ad(!block->page.in_page_hash);
|
||||
ut_ad(!block->page.in_zip_hash);
|
||||
ut_d(block->page.in_zip_hash = TRUE);
|
||||
|
||||
mutex_enter(&zip_hash_mutex);
|
||||
HASH_INSERT(buf_page_t, hash, buf_pool->zip_hash, fold, &block->page);
|
||||
mutex_exit(&zip_hash_mutex);
|
||||
|
||||
ut_d(buf_buddy_n_frames++);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Allocate a block from a bigger object. */
|
||||
static
|
||||
void*
|
||||
buf_buddy_alloc_from(
|
||||
/*=================*/
|
||||
/* out: allocated block */
|
||||
void* buf, /* in: a block that is free to use */
|
||||
ulint i, /* in: index of buf_pool->zip_free[] */
|
||||
ulint j) /* in: size of buf as an index
|
||||
of buf_pool->zip_free[] */
|
||||
{
|
||||
ulint offs = BUF_BUDDY_LOW << j;
|
||||
ut_ad(j <= BUF_BUDDY_SIZES);
|
||||
ut_ad(j >= i);
|
||||
ut_ad(!ut_align_offset(buf, offs));
|
||||
|
||||
/* Add the unused parts of the block to the free lists. */
|
||||
while (j > i) {
|
||||
buf_page_t* bpage;
|
||||
|
||||
offs >>= 1;
|
||||
j--;
|
||||
|
||||
bpage = (buf_page_t*) ((byte*) buf + offs);
|
||||
ut_d(memset(bpage, j, BUF_BUDDY_LOW << j));
|
||||
bpage->state = BUF_BLOCK_ZIP_FREE;
|
||||
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
|
||||
/* Valgrind would complain about accessing free memory. */
|
||||
UT_LIST_VALIDATE(zip_list, buf_page_t, buf_pool->zip_free[j]);
|
||||
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
|
||||
buf_buddy_add_to_free(bpage, j);
|
||||
}
|
||||
|
||||
return(buf);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Allocate a block. The thread calling this function must hold
|
||||
buf_pool_mutex and must not hold buf_pool_zip_mutex or any block->mutex.
|
||||
The buf_pool_mutex may only be released and reacquired if lru != NULL. */
|
||||
UNIV_INTERN
|
||||
void*
|
||||
buf_buddy_alloc_low(
|
||||
/*================*/
|
||||
/* out: allocated block,
|
||||
possibly NULL if lru==NULL */
|
||||
ulint i, /* in: index of buf_pool->zip_free[],
|
||||
or BUF_BUDDY_SIZES */
|
||||
ibool* lru, /* in: pointer to a variable that will be assigned
|
||||
TRUE if storage was allocated from the LRU list
|
||||
and buf_pool_mutex was temporarily released,
|
||||
or NULL if the LRU list should not be used */
|
||||
ibool have_page_hash_mutex)
|
||||
{
|
||||
buf_block_t* block;
|
||||
|
||||
//ut_ad(buf_pool_mutex_own());
|
||||
ut_ad(!mutex_own(&buf_pool_zip_mutex));
|
||||
|
||||
if (i < BUF_BUDDY_SIZES) {
|
||||
/* Try to allocate from the buddy system. */
|
||||
mutex_enter(&zip_free_mutex);
|
||||
block = buf_buddy_alloc_zip(i);
|
||||
|
||||
if (block) {
|
||||
|
||||
goto func_exit;
|
||||
}
|
||||
|
||||
mutex_exit(&zip_free_mutex);
|
||||
}
|
||||
|
||||
/* Try allocating from the buf_pool->free list. */
|
||||
block = buf_LRU_get_free_only();
|
||||
|
||||
if (block) {
|
||||
|
||||
goto alloc_big;
|
||||
}
|
||||
|
||||
if (!lru) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Try replacing an uncompressed page in the buffer pool. */
|
||||
//buf_pool_mutex_exit();
|
||||
mutex_exit(&LRU_list_mutex);
|
||||
if (have_page_hash_mutex) {
|
||||
rw_lock_x_unlock(&page_hash_latch);
|
||||
}
|
||||
block = buf_LRU_get_free_block(0);
|
||||
*lru = TRUE;
|
||||
//buf_pool_mutex_enter();
|
||||
mutex_enter(&LRU_list_mutex);
|
||||
if (have_page_hash_mutex) {
|
||||
rw_lock_x_lock(&page_hash_latch);
|
||||
}
|
||||
|
||||
alloc_big:
|
||||
buf_buddy_block_register(block);
|
||||
|
||||
mutex_enter(&zip_free_mutex);
|
||||
block = buf_buddy_alloc_from(block->frame, i, BUF_BUDDY_SIZES);
|
||||
|
||||
func_exit:
|
||||
buf_buddy_stat[i].used++;
|
||||
mutex_exit(&zip_free_mutex);
|
||||
|
||||
return(block);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Try to relocate the control block of a compressed page. */
|
||||
static
|
||||
ibool
|
||||
buf_buddy_relocate_block(
|
||||
/*=====================*/
|
||||
/* out: TRUE if relocated */
|
||||
buf_page_t* bpage, /* in: block to relocate */
|
||||
buf_page_t* dpage) /* in: free block to relocate to */
|
||||
{
|
||||
buf_page_t* b;
|
||||
|
||||
//ut_ad(buf_pool_mutex_own());
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&page_hash_latch, RW_LOCK_EX));
|
||||
#endif
|
||||
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_FREE:
|
||||
case BUF_BLOCK_NOT_USED:
|
||||
case BUF_BLOCK_READY_FOR_USE:
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
case BUF_BLOCK_MEMORY:
|
||||
case BUF_BLOCK_REMOVE_HASH:
|
||||
/* ut_error; */ /* optimistic */
|
||||
case BUF_BLOCK_ZIP_DIRTY:
|
||||
/* Cannot relocate dirty pages. */
|
||||
return(FALSE);
|
||||
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
break;
|
||||
}
|
||||
|
||||
mutex_enter(&buf_pool_zip_mutex);
|
||||
mutex_enter(&zip_free_mutex);
|
||||
|
||||
if (!buf_page_can_relocate(bpage)) {
|
||||
mutex_exit(&buf_pool_zip_mutex);
|
||||
mutex_exit(&zip_free_mutex);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (bpage != buf_page_hash_get(bpage->space, bpage->offset)) {
|
||||
mutex_exit(&buf_pool_zip_mutex);
|
||||
mutex_exit(&zip_free_mutex);
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
buf_relocate(bpage, dpage);
|
||||
ut_d(bpage->state = BUF_BLOCK_ZIP_FREE);
|
||||
|
||||
/* relocate buf_pool->zip_clean */
|
||||
mutex_enter(&flush_list_mutex);
|
||||
b = UT_LIST_GET_PREV(zip_list, dpage);
|
||||
UT_LIST_REMOVE(zip_list, buf_pool->zip_clean, dpage);
|
||||
|
||||
if (b) {
|
||||
UT_LIST_INSERT_AFTER(zip_list, buf_pool->zip_clean, b, dpage);
|
||||
} else {
|
||||
UT_LIST_ADD_FIRST(zip_list, buf_pool->zip_clean, dpage);
|
||||
}
|
||||
mutex_exit(&flush_list_mutex);
|
||||
|
||||
mutex_exit(&buf_pool_zip_mutex);
|
||||
mutex_exit(&zip_free_mutex);
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Try to relocate a block. */
|
||||
static
|
||||
ibool
|
||||
buf_buddy_relocate(
|
||||
/*===============*/
|
||||
/* out: TRUE if relocated */
|
||||
void* src, /* in: block to relocate */
|
||||
void* dst, /* in: free block to relocate to */
|
||||
ulint i, /* in: index of buf_pool->zip_free[] */
|
||||
ibool have_page_hash_mutex)
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
const ulint size = BUF_BUDDY_LOW << i;
|
||||
ullint usec = ut_time_us(NULL);
|
||||
|
||||
//ut_ad(buf_pool_mutex_own());
|
||||
ut_ad(mutex_own(&zip_free_mutex));
|
||||
ut_ad(!mutex_own(&buf_pool_zip_mutex));
|
||||
ut_ad(!ut_align_offset(src, size));
|
||||
ut_ad(!ut_align_offset(dst, size));
|
||||
UNIV_MEM_ASSERT_W(dst, size);
|
||||
|
||||
/* We assume that all memory from buf_buddy_alloc()
|
||||
is used for either compressed pages or buf_page_t
|
||||
objects covering compressed pages. */
|
||||
|
||||
/* We look inside the allocated objects returned by
|
||||
buf_buddy_alloc() and assume that anything of
|
||||
PAGE_ZIP_MIN_SIZE or larger is a compressed page that contains
|
||||
a valid space_id and page_no in the page header. Should the
|
||||
fields be invalid, we will be unable to relocate the block.
|
||||
We also assume that anything that fits sizeof(buf_page_t)
|
||||
actually is a properly initialized buf_page_t object. */
|
||||
|
||||
if (size >= PAGE_ZIP_MIN_SIZE) {
|
||||
if (!have_page_hash_mutex)
|
||||
mutex_exit(&zip_free_mutex);
|
||||
|
||||
/* This is a compressed page. */
|
||||
mutex_t* mutex;
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_enter(&LRU_list_mutex);
|
||||
rw_lock_x_lock(&page_hash_latch);
|
||||
}
|
||||
/* The src block may be split into smaller blocks,
|
||||
some of which may be free. Thus, the
|
||||
mach_read_from_4() calls below may attempt to read
|
||||
from free memory. The memory is "owned" by the buddy
|
||||
allocator (and it has been allocated from the buffer
|
||||
pool), so there is nothing wrong about this. The
|
||||
mach_read_from_4() calls here will only trigger bogus
|
||||
Valgrind memcheck warnings in UNIV_DEBUG_VALGRIND builds. */
|
||||
bpage = buf_page_hash_get(
|
||||
mach_read_from_4((const byte*) src
|
||||
+ FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID),
|
||||
mach_read_from_4((const byte*) src
|
||||
+ FIL_PAGE_OFFSET));
|
||||
|
||||
if (!bpage || bpage->zip.data != src) {
|
||||
/* The block has probably been freshly
|
||||
allocated by buf_LRU_get_free_block() but not
|
||||
added to buf_pool->page_hash yet. Obviously,
|
||||
it cannot be relocated. */
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_enter(&zip_free_mutex);
|
||||
mutex_exit(&LRU_list_mutex);
|
||||
rw_lock_x_unlock(&page_hash_latch);
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (page_zip_get_size(&bpage->zip) != size) {
|
||||
/* The block is of different size. We would
|
||||
have to relocate all blocks covered by src.
|
||||
For the sake of simplicity, give up. */
|
||||
ut_ad(page_zip_get_size(&bpage->zip) < size);
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_enter(&zip_free_mutex);
|
||||
mutex_exit(&LRU_list_mutex);
|
||||
rw_lock_x_unlock(&page_hash_latch);
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/* To keep latch order */
|
||||
if (have_page_hash_mutex)
|
||||
mutex_exit(&zip_free_mutex);
|
||||
|
||||
/* The block must have been allocated, but it may
|
||||
contain uninitialized data. */
|
||||
UNIV_MEM_ASSERT_W(src, size);
|
||||
|
||||
mutex = buf_page_get_mutex(bpage);
|
||||
|
||||
retry_lock:
|
||||
mutex_enter(mutex);
|
||||
if (mutex != buf_page_get_mutex(bpage)) {
|
||||
mutex_exit(mutex);
|
||||
mutex = buf_page_get_mutex(bpage);
|
||||
goto retry_lock;
|
||||
}
|
||||
mutex_enter(&zip_free_mutex);
|
||||
|
||||
if (buf_page_can_relocate(bpage)) {
|
||||
/* Relocate the compressed page. */
|
||||
ut_a(bpage->zip.data == src);
|
||||
memcpy(dst, src, size);
|
||||
bpage->zip.data = dst;
|
||||
mutex_exit(mutex);
|
||||
success:
|
||||
UNIV_MEM_INVALID(src, size);
|
||||
{
|
||||
buf_buddy_stat_t* buddy_stat
|
||||
= &buf_buddy_stat[i];
|
||||
buddy_stat->relocated++;
|
||||
buddy_stat->relocated_usec
|
||||
+= ut_time_us(NULL) - usec;
|
||||
}
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_exit(&LRU_list_mutex);
|
||||
rw_lock_x_unlock(&page_hash_latch);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_exit(&LRU_list_mutex);
|
||||
rw_lock_x_unlock(&page_hash_latch);
|
||||
}
|
||||
|
||||
mutex_exit(mutex);
|
||||
} else if (i == buf_buddy_get_slot(sizeof(buf_page_t))) {
|
||||
/* This must be a buf_page_t object. */
|
||||
UNIV_MEM_ASSERT_RW(src, size);
|
||||
|
||||
mutex_exit(&zip_free_mutex);
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_enter(&LRU_list_mutex);
|
||||
rw_lock_x_lock(&page_hash_latch);
|
||||
}
|
||||
|
||||
if (buf_buddy_relocate_block(src, dst)) {
|
||||
mutex_enter(&zip_free_mutex);
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_exit(&LRU_list_mutex);
|
||||
rw_lock_x_unlock(&page_hash_latch);
|
||||
}
|
||||
|
||||
goto success;
|
||||
}
|
||||
|
||||
mutex_enter(&zip_free_mutex);
|
||||
|
||||
if (!have_page_hash_mutex) {
|
||||
mutex_exit(&LRU_list_mutex);
|
||||
rw_lock_x_unlock(&page_hash_latch);
|
||||
}
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Deallocate a block. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
buf_buddy_free_low(
|
||||
/*===============*/
|
||||
void* buf, /* in: block to be freed, must not be
|
||||
pointed to by the buffer pool */
|
||||
ulint i, /* in: index of buf_pool->zip_free[] */
|
||||
ibool have_page_hash_mutex)
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
buf_page_t* buddy;
|
||||
|
||||
//ut_ad(buf_pool_mutex_own());
|
||||
ut_ad(mutex_own(&zip_free_mutex));
|
||||
ut_ad(!mutex_own(&buf_pool_zip_mutex));
|
||||
ut_ad(i <= BUF_BUDDY_SIZES);
|
||||
ut_ad(buf_buddy_stat[i].used > 0);
|
||||
|
||||
buf_buddy_stat[i].used--;
|
||||
recombine:
|
||||
UNIV_MEM_ASSERT_AND_ALLOC(buf, BUF_BUDDY_LOW << i);
|
||||
ut_d(((buf_page_t*) buf)->state = BUF_BLOCK_ZIP_FREE);
|
||||
|
||||
if (i == BUF_BUDDY_SIZES) {
|
||||
mutex_exit(&zip_free_mutex);
|
||||
buf_buddy_block_free(buf, have_page_hash_mutex);
|
||||
mutex_enter(&zip_free_mutex);
|
||||
return;
|
||||
}
|
||||
|
||||
ut_ad(i < BUF_BUDDY_SIZES);
|
||||
ut_ad(buf == ut_align_down(buf, BUF_BUDDY_LOW << i));
|
||||
ut_ad(!buf_pool_contains_zip(buf));
|
||||
|
||||
/* Try to combine adjacent blocks. */
|
||||
|
||||
buddy = (buf_page_t*) buf_buddy_get(((byte*) buf), BUF_BUDDY_LOW << i);
|
||||
|
||||
#ifndef UNIV_DEBUG_VALGRIND
|
||||
/* Valgrind would complain about accessing free memory. */
|
||||
|
||||
if (buddy->state != BUF_BLOCK_ZIP_FREE) {
|
||||
|
||||
goto buddy_nonfree;
|
||||
}
|
||||
|
||||
/* The field buddy->state can only be trusted for free blocks.
|
||||
If buddy->state == BUF_BLOCK_ZIP_FREE, the block is free if
|
||||
it is in the free list. */
|
||||
#endif /* !UNIV_DEBUG_VALGRIND */
|
||||
|
||||
for (bpage = UT_LIST_GET_FIRST(buf_pool->zip_free[i]); bpage; ) {
|
||||
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
|
||||
ut_ad(buf_page_get_state(bpage) == BUF_BLOCK_ZIP_FREE);
|
||||
|
||||
if (bpage == buddy) {
|
||||
buddy_free:
|
||||
/* The buddy is free: recombine */
|
||||
buf_buddy_remove_from_free(bpage, i);
|
||||
buddy_free2:
|
||||
ut_ad(buf_page_get_state(buddy) == BUF_BLOCK_ZIP_FREE);
|
||||
ut_ad(!buf_pool_contains_zip(buddy));
|
||||
i++;
|
||||
buf = ut_align_down(buf, BUF_BUDDY_LOW << i);
|
||||
|
||||
goto recombine;
|
||||
}
|
||||
|
||||
ut_a(bpage != buf);
|
||||
|
||||
{
|
||||
buf_page_t* next = UT_LIST_GET_NEXT(zip_list, bpage);
|
||||
UNIV_MEM_ASSERT_AND_FREE(bpage, BUF_BUDDY_LOW << i);
|
||||
bpage = next;
|
||||
}
|
||||
}
|
||||
|
||||
#ifndef UNIV_DEBUG_VALGRIND
|
||||
buddy_nonfree:
|
||||
/* Valgrind would complain about accessing free memory. */
|
||||
ut_d(UT_LIST_VALIDATE(zip_list, buf_page_t, buf_pool->zip_free[i]));
|
||||
#endif /* UNIV_DEBUG_VALGRIND */
|
||||
|
||||
/* The buddy is not free. Is there a free block of this size? */
|
||||
bpage = UT_LIST_GET_LAST(buf_pool->zip_free[i]);
|
||||
|
||||
if (bpage) {
|
||||
/* Remove the block from the free list, because a successful
|
||||
buf_buddy_relocate() will overwrite bpage->list. */
|
||||
|
||||
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
|
||||
buf_buddy_remove_from_free(bpage, i);
|
||||
|
||||
/* Try to relocate the buddy of buf to the free block. */
|
||||
if (buf_buddy_relocate(buddy, bpage, i, have_page_hash_mutex)) {
|
||||
|
||||
ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
|
||||
goto buddy_free2;
|
||||
}
|
||||
|
||||
buf_buddy_add_to_free(bpage, i);
|
||||
|
||||
/* Try to relocate the buddy of the free block to buf. */
|
||||
buddy = (buf_page_t*) buf_buddy_get(((byte*) bpage),
|
||||
BUF_BUDDY_LOW << i);
|
||||
|
||||
#if defined UNIV_DEBUG && !defined UNIV_DEBUG_VALGRIND
|
||||
{
|
||||
const buf_page_t* b;
|
||||
|
||||
/* The buddy must not be (completely) free, because
|
||||
we always recombine adjacent free blocks.
|
||||
(Parts of the buddy can be free in
|
||||
buf_pool->zip_free[j] with j < i.)*/
|
||||
for (b = UT_LIST_GET_FIRST(buf_pool->zip_free[i]);
|
||||
b; b = UT_LIST_GET_NEXT(zip_list, b)) {
|
||||
|
||||
ut_a(b != buddy);
|
||||
}
|
||||
}
|
||||
#endif /* UNIV_DEBUG && !UNIV_DEBUG_VALGRIND */
|
||||
|
||||
if (buf_buddy_relocate(buddy, buf, i, have_page_hash_mutex)) {
|
||||
|
||||
buf = bpage;
|
||||
UNIV_MEM_VALID(bpage, BUF_BUDDY_LOW << i);
|
||||
ut_d(buddy->state = BUF_BLOCK_ZIP_FREE);
|
||||
goto buddy_free;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free the block to the buddy list. */
|
||||
bpage = buf;
|
||||
#ifdef UNIV_DEBUG
|
||||
if (i < buf_buddy_get_slot(PAGE_ZIP_MIN_SIZE)) {
|
||||
/* This area has most likely been allocated for at
|
||||
least one compressed-only block descriptor. Check
|
||||
that there are no live objects in the area. This is
|
||||
not a complete check: it may yield false positives as
|
||||
well as false negatives. Also, due to buddy blocks
|
||||
being recombined, it is possible (although unlikely)
|
||||
that this branch is never reached. */
|
||||
|
||||
char* c;
|
||||
|
||||
# ifndef UNIV_DEBUG_VALGRIND
|
||||
/* Valgrind would complain about accessing
|
||||
uninitialized memory. Besides, Valgrind performs a
|
||||
more exhaustive check, at every memory access. */
|
||||
const buf_page_t* b = buf;
|
||||
const buf_page_t* const b_end = (buf_page_t*)
|
||||
((char*) b + (BUF_BUDDY_LOW << i));
|
||||
|
||||
for (; b < b_end; b++) {
|
||||
/* Avoid false positives (and cause false
|
||||
negatives) by checking for b->space < 1000. */
|
||||
|
||||
if ((b->state == BUF_BLOCK_ZIP_PAGE
|
||||
|| b->state == BUF_BLOCK_ZIP_DIRTY)
|
||||
&& b->space > 0 && b->space < 1000) {
|
||||
fprintf(stderr,
|
||||
"buddy dirty %p %u (%u,%u) %p,%lu\n",
|
||||
(void*) b,
|
||||
b->state, b->space, b->offset,
|
||||
buf, i);
|
||||
}
|
||||
}
|
||||
# endif /* !UNIV_DEBUG_VALGRIND */
|
||||
|
||||
/* Scramble the block. This should make any pointers
|
||||
invalid and trigger a segmentation violation. Because
|
||||
the scrambling can be reversed, it may be possible to
|
||||
track down the object pointing to the freed data by
|
||||
dereferencing the unscrambled bpage->LRU or
|
||||
bpage->list pointers. */
|
||||
for (c = (char*) buf + (BUF_BUDDY_LOW << i);
|
||||
c-- > (char*) buf; ) {
|
||||
*c = ~*c ^ i;
|
||||
}
|
||||
} else {
|
||||
/* Fill large blocks with a constant pattern. */
|
||||
memset(bpage, i, BUF_BUDDY_LOW << i);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
bpage->state = BUF_BLOCK_ZIP_FREE;
|
||||
buf_buddy_add_to_free(bpage, i);
|
||||
}
|
||||
4143
storage/xtradb/buf/buf0buf.c
Normal file
4143
storage/xtradb/buf/buf0buf.c
Normal file
File diff suppressed because it is too large
Load diff
1358
storage/xtradb/buf/buf0flu.c
Normal file
1358
storage/xtradb/buf/buf0flu.c
Normal file
File diff suppressed because it is too large
Load diff
2229
storage/xtradb/buf/buf0lru.c
Normal file
2229
storage/xtradb/buf/buf0lru.c
Normal file
File diff suppressed because it is too large
Load diff
872
storage/xtradb/buf/buf0rea.c
Normal file
872
storage/xtradb/buf/buf0rea.c
Normal file
|
|
@ -0,0 +1,872 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
The database buffer read
|
||||
|
||||
Created 11/5/1995 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "buf0rea.h"
|
||||
|
||||
#include "fil0fil.h"
|
||||
#include "mtr0mtr.h"
|
||||
|
||||
#include "buf0buf.h"
|
||||
#include "buf0flu.h"
|
||||
#include "buf0lru.h"
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "log0recv.h"
|
||||
#include "trx0sys.h"
|
||||
#include "os0file.h"
|
||||
#include "srv0start.h"
|
||||
|
||||
extern ulint srv_read_ahead;
|
||||
extern ulint srv_read_ahead_rnd;
|
||||
extern ulint srv_read_ahead_seq;
|
||||
extern ulint srv_buf_pool_reads;
|
||||
|
||||
/* The size in blocks of the area where the random read-ahead algorithm counts
|
||||
the accessed pages when deciding whether to read-ahead */
|
||||
#define BUF_READ_AHEAD_RANDOM_AREA BUF_READ_AHEAD_AREA
|
||||
|
||||
/* There must be at least this many pages in buf_pool in the area to start
|
||||
a random read-ahead */
|
||||
#define BUF_READ_AHEAD_RANDOM_THRESHOLD (5 + buf_read_ahead_random_area / 8)
|
||||
|
||||
/* The linear read-ahead area size */
|
||||
#define BUF_READ_AHEAD_LINEAR_AREA BUF_READ_AHEAD_AREA
|
||||
|
||||
/* The linear read-ahead threshold */
|
||||
#define LINEAR_AREA_THRESHOLD_COEF 5 / 8
|
||||
|
||||
/* If there are buf_pool->curr_size per the number below pending reads, then
|
||||
read-ahead is not done: this is to prevent flooding the buffer pool with
|
||||
i/o-fixed buffer blocks */
|
||||
#define BUF_READ_AHEAD_PEND_LIMIT 2
|
||||
|
||||
/************************************************************************
|
||||
Low-level function which reads a page asynchronously from a file to the
|
||||
buffer buf_pool if it is not already there, in which case does nothing.
|
||||
Sets the io_fix flag and sets an exclusive lock on the buffer frame. The
|
||||
flag is cleared and the x-lock released by an i/o-handler thread. */
|
||||
static
|
||||
ulint
|
||||
buf_read_page_low(
|
||||
/*==============*/
|
||||
/* out: 1 if a read request was queued, 0 if the page
|
||||
already resided in buf_pool, or if the page is in
|
||||
the doublewrite buffer blocks in which case it is never
|
||||
read into the pool, or if the tablespace does not
|
||||
exist or is being dropped */
|
||||
ulint* err, /* out: DB_SUCCESS or DB_TABLESPACE_DELETED if we are
|
||||
trying to read from a non-existent tablespace, or a
|
||||
tablespace which is just now being dropped */
|
||||
ibool sync, /* in: TRUE if synchronous aio is desired */
|
||||
ulint mode, /* in: BUF_READ_IBUF_PAGES_ONLY, ...,
|
||||
ORed to OS_AIO_SIMULATED_WAKE_LATER (see below
|
||||
at read-ahead functions) */
|
||||
ulint space, /* in: space id */
|
||||
ulint zip_size,/* in: compressed page size, or 0 */
|
||||
ibool unzip, /* in: TRUE=request uncompressed page */
|
||||
ib_int64_t tablespace_version, /* in: if the space memory object has
|
||||
this timestamp different from what we are giving here,
|
||||
treat the tablespace as dropped; this is a timestamp we
|
||||
use to stop dangling page reads from a tablespace
|
||||
which we have DISCARDed + IMPORTed back */
|
||||
ulint offset) /* in: page number */
|
||||
{
|
||||
buf_page_t* bpage;
|
||||
ulint wake_later;
|
||||
|
||||
*err = DB_SUCCESS;
|
||||
|
||||
wake_later = mode & OS_AIO_SIMULATED_WAKE_LATER;
|
||||
mode = mode & ~OS_AIO_SIMULATED_WAKE_LATER;
|
||||
|
||||
if (trx_doublewrite && space == TRX_SYS_SPACE
|
||||
&& ( (offset >= trx_doublewrite->block1
|
||||
&& offset < trx_doublewrite->block1
|
||||
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE)
|
||||
|| (offset >= trx_doublewrite->block2
|
||||
&& offset < trx_doublewrite->block2
|
||||
+ TRX_SYS_DOUBLEWRITE_BLOCK_SIZE))) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Warning: trying to read"
|
||||
" doublewrite buffer page %lu\n",
|
||||
(ulong) offset);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (ibuf_bitmap_page(zip_size, offset)
|
||||
|| trx_sys_hdr_page(space, offset)) {
|
||||
|
||||
/* Trx sys header is so low in the latching order that we play
|
||||
safe and do not leave the i/o-completion to an asynchronous
|
||||
i/o-thread. Ibuf bitmap pages must always be read with
|
||||
syncronous i/o, to make sure they do not get involved in
|
||||
thread deadlocks. */
|
||||
|
||||
sync = TRUE;
|
||||
}
|
||||
|
||||
/* The following call will also check if the tablespace does not exist
|
||||
or is being dropped; if we succeed in initing the page in the buffer
|
||||
pool for read, then DISCARD cannot proceed until the read has
|
||||
completed */
|
||||
bpage = buf_page_init_for_read(err, mode, space, zip_size, unzip,
|
||||
tablespace_version, offset);
|
||||
if (bpage == NULL) {
|
||||
/* bugfix: http://bugs.mysql.com/bug.php?id=43948 */
|
||||
if (recv_recovery_is_on() && *err == DB_TABLESPACE_DELETED) {
|
||||
/* hashed log recs must be treated here */
|
||||
recv_addr_t* recv_addr;
|
||||
|
||||
mutex_enter(&(recv_sys->mutex));
|
||||
|
||||
if (recv_sys->apply_log_recs == FALSE) {
|
||||
mutex_exit(&(recv_sys->mutex));
|
||||
goto not_to_recover;
|
||||
}
|
||||
|
||||
/* recv_get_fil_addr_struct() */
|
||||
recv_addr = HASH_GET_FIRST(recv_sys->addr_hash,
|
||||
hash_calc_hash(ut_fold_ulint_pair(space, offset),
|
||||
recv_sys->addr_hash));
|
||||
while (recv_addr) {
|
||||
if ((recv_addr->space == space)
|
||||
&& (recv_addr->page_no == offset)) {
|
||||
break;
|
||||
}
|
||||
recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
|
||||
}
|
||||
|
||||
if ((recv_addr == NULL)
|
||||
|| (recv_addr->state == RECV_BEING_PROCESSED)
|
||||
|| (recv_addr->state == RECV_PROCESSED)) {
|
||||
mutex_exit(&(recv_sys->mutex));
|
||||
goto not_to_recover;
|
||||
}
|
||||
|
||||
fprintf(stderr, " (cannot find space: %lu)", space);
|
||||
recv_addr->state = RECV_PROCESSED;
|
||||
|
||||
ut_a(recv_sys->n_addrs);
|
||||
recv_sys->n_addrs--;
|
||||
|
||||
mutex_exit(&(recv_sys->mutex));
|
||||
}
|
||||
not_to_recover:
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
if (buf_debug_prints) {
|
||||
fprintf(stderr,
|
||||
"Posting read request for page %lu, sync %lu\n",
|
||||
(ulong) offset,
|
||||
(ulong) sync);
|
||||
}
|
||||
#endif
|
||||
|
||||
ut_ad(buf_page_in_file(bpage));
|
||||
|
||||
if (zip_size) {
|
||||
*err = fil_io(OS_FILE_READ | wake_later,
|
||||
sync, space, zip_size, offset, 0, zip_size,
|
||||
bpage->zip.data, bpage);
|
||||
} else {
|
||||
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
|
||||
|
||||
*err = fil_io(OS_FILE_READ | wake_later,
|
||||
sync, space, 0, offset, 0, UNIV_PAGE_SIZE,
|
||||
((buf_block_t*) bpage)->frame, bpage);
|
||||
}
|
||||
ut_a(*err == DB_SUCCESS);
|
||||
|
||||
if (sync) {
|
||||
/* The i/o is already completed when we arrive from
|
||||
fil_read */
|
||||
buf_page_io_complete(bpage);
|
||||
}
|
||||
|
||||
return(1);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Applies a random read-ahead in buf_pool if there are at least a threshold
|
||||
value of accessed pages from the random read-ahead area. Does not read any
|
||||
page, not even the one at the position (space, offset), if the read-ahead
|
||||
mechanism is not activated. NOTE 1: the calling thread may own latches on
|
||||
pages: to avoid deadlocks this function must be written such that it cannot
|
||||
end up waiting for these latches! NOTE 2: the calling thread must want
|
||||
access to the page given: this rule is set to prevent unintended read-aheads
|
||||
performed by ibuf routines, a situation which could result in a deadlock if
|
||||
the OS does not support asynchronous i/o. */
|
||||
static
|
||||
ulint
|
||||
buf_read_ahead_random(
|
||||
/*==================*/
|
||||
/* out: number of page read requests issued; NOTE
|
||||
that if we read ibuf pages, it may happen that
|
||||
the page at the given page number does not get
|
||||
read even if we return a value > 0! */
|
||||
ulint space, /* in: space id */
|
||||
ulint zip_size,/* in: compressed page size in bytes, or 0 */
|
||||
ulint offset) /* in: page number of a page which the current thread
|
||||
wants to access */
|
||||
{
|
||||
ib_int64_t tablespace_version;
|
||||
ulint recent_blocks = 0;
|
||||
ulint count;
|
||||
ulint LRU_recent_limit;
|
||||
ulint ibuf_mode;
|
||||
ulint low, high;
|
||||
ulint err;
|
||||
ulint i;
|
||||
ulint buf_read_ahead_random_area;
|
||||
|
||||
if (!(srv_read_ahead & 1)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (srv_startup_is_before_trx_rollback_phase) {
|
||||
/* No read-ahead to avoid thread deadlocks */
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (ibuf_bitmap_page(zip_size, offset)
|
||||
|| trx_sys_hdr_page(space, offset)) {
|
||||
|
||||
/* If it is an ibuf bitmap page or trx sys hdr, we do
|
||||
no read-ahead, as that could break the ibuf page access
|
||||
order */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Remember the tablespace version before we ask te tablespace size
|
||||
below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we
|
||||
do not try to read outside the bounds of the tablespace! */
|
||||
|
||||
tablespace_version = fil_space_get_version(space);
|
||||
|
||||
buf_read_ahead_random_area = BUF_READ_AHEAD_RANDOM_AREA;
|
||||
|
||||
low = (offset / buf_read_ahead_random_area)
|
||||
* buf_read_ahead_random_area;
|
||||
high = (offset / buf_read_ahead_random_area + 1)
|
||||
* buf_read_ahead_random_area;
|
||||
if (high > fil_space_get_size(space)) {
|
||||
|
||||
high = fil_space_get_size(space);
|
||||
}
|
||||
|
||||
/* Get the minimum LRU_position field value for an initial segment
|
||||
of the LRU list, to determine which blocks have recently been added
|
||||
to the start of the list. */
|
||||
|
||||
LRU_recent_limit = buf_LRU_get_recent_limit();
|
||||
|
||||
//buf_pool_mutex_enter();
|
||||
mutex_enter(&buf_pool_mutex);
|
||||
|
||||
if (buf_pool->n_pend_reads
|
||||
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
|
||||
//buf_pool_mutex_exit();
|
||||
mutex_exit(&buf_pool_mutex);
|
||||
|
||||
return(0);
|
||||
}
|
||||
mutex_exit(&buf_pool_mutex);
|
||||
|
||||
/* Count how many blocks in the area have been recently accessed,
|
||||
that is, reside near the start of the LRU list. */
|
||||
|
||||
rw_lock_s_lock(&page_hash_latch);
|
||||
for (i = low; i < high; i++) {
|
||||
const buf_page_t* bpage = buf_page_hash_get(space, i);
|
||||
|
||||
if (bpage
|
||||
&& buf_page_is_accessed(bpage)
|
||||
&& (buf_page_get_LRU_position(bpage) > LRU_recent_limit)) {
|
||||
|
||||
recent_blocks++;
|
||||
|
||||
if (recent_blocks >= BUF_READ_AHEAD_RANDOM_THRESHOLD) {
|
||||
|
||||
//buf_pool_mutex_exit();
|
||||
rw_lock_s_unlock(&page_hash_latch);
|
||||
goto read_ahead;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//buf_pool_mutex_exit();
|
||||
rw_lock_s_unlock(&page_hash_latch);
|
||||
/* Do nothing */
|
||||
return(0);
|
||||
|
||||
read_ahead:
|
||||
/* Read all the suitable blocks within the area */
|
||||
|
||||
if (ibuf_inside()) {
|
||||
ibuf_mode = BUF_READ_IBUF_PAGES_ONLY;
|
||||
} else {
|
||||
ibuf_mode = BUF_READ_ANY_PAGE;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for (i = low; i < high; i++) {
|
||||
/* It is only sensible to do read-ahead in the non-sync aio
|
||||
mode: hence FALSE as the first parameter */
|
||||
|
||||
if (!ibuf_bitmap_page(zip_size, i)) {
|
||||
count += buf_read_page_low(
|
||||
&err, FALSE,
|
||||
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
|
||||
space, zip_size, FALSE,
|
||||
tablespace_version, i);
|
||||
if (err == DB_TABLESPACE_DELETED) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Warning: in random"
|
||||
" readahead trying to access\n"
|
||||
"InnoDB: tablespace %lu page %lu,\n"
|
||||
"InnoDB: but the tablespace does not"
|
||||
" exist or is just being dropped.\n",
|
||||
(ulong) space, (ulong) i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In simulated aio we wake the aio handler threads only after
|
||||
queuing all aio requests, in native aio the following call does
|
||||
nothing: */
|
||||
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
if (buf_debug_prints && (count > 0)) {
|
||||
fprintf(stderr,
|
||||
"Random read-ahead space %lu offset %lu pages %lu\n",
|
||||
(ulong) space, (ulong) offset,
|
||||
(ulong) count);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
++srv_read_ahead_rnd;
|
||||
return(count);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
High-level function which reads a page asynchronously from a file to the
|
||||
buffer buf_pool if it is not already there. Sets the io_fix flag and sets
|
||||
an exclusive lock on the buffer frame. The flag is cleared and the x-lock
|
||||
released by the i/o-handler thread. Does a random read-ahead if it seems
|
||||
sensible. */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
buf_read_page(
|
||||
/*==========*/
|
||||
/* out: number of page read requests issued: this can
|
||||
be > 1 if read-ahead occurred */
|
||||
ulint space, /* in: space id */
|
||||
ulint zip_size,/* in: compressed page size in bytes, or 0 */
|
||||
ulint offset) /* in: page number */
|
||||
{
|
||||
ib_int64_t tablespace_version;
|
||||
ulint count;
|
||||
ulint count2;
|
||||
ulint err;
|
||||
|
||||
tablespace_version = fil_space_get_version(space);
|
||||
|
||||
count = buf_read_ahead_random(space, zip_size, offset);
|
||||
|
||||
/* We do the i/o in the synchronous aio mode to save thread
|
||||
switches: hence TRUE */
|
||||
|
||||
count2 = buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
|
||||
zip_size, FALSE,
|
||||
tablespace_version, offset);
|
||||
srv_buf_pool_reads+= count2;
|
||||
if (err == DB_TABLESPACE_DELETED) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Error: trying to access"
|
||||
" tablespace %lu page no. %lu,\n"
|
||||
"InnoDB: but the tablespace does not exist"
|
||||
" or is just being dropped.\n",
|
||||
(ulong) space, (ulong) offset);
|
||||
}
|
||||
|
||||
/* Flush pages from the end of the LRU list if necessary */
|
||||
buf_flush_free_margin(FALSE);
|
||||
|
||||
/* Increment number of I/O operations used for LRU policy. */
|
||||
buf_LRU_stat_inc_io();
|
||||
|
||||
return(count + count2);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Applies linear read-ahead if in the buf_pool the page is a border page of
|
||||
a linear read-ahead area and all the pages in the area have been accessed.
|
||||
Does not read any page if the read-ahead mechanism is not activated. Note
|
||||
that the the algorithm looks at the 'natural' adjacent successor and
|
||||
predecessor of the page, which on the leaf level of a B-tree are the next
|
||||
and previous page in the chain of leaves. To know these, the page specified
|
||||
in (space, offset) must already be present in the buf_pool. Thus, the
|
||||
natural way to use this function is to call it when a page in the buf_pool
|
||||
is accessed the first time, calling this function just after it has been
|
||||
bufferfixed.
|
||||
NOTE 1: as this function looks at the natural predecessor and successor
|
||||
fields on the page, what happens, if these are not initialized to any
|
||||
sensible value? No problem, before applying read-ahead we check that the
|
||||
area to read is within the span of the space, if not, read-ahead is not
|
||||
applied. An uninitialized value may result in a useless read operation, but
|
||||
only very improbably.
|
||||
NOTE 2: the calling thread may own latches on pages: to avoid deadlocks this
|
||||
function must be written such that it cannot end up waiting for these
|
||||
latches!
|
||||
NOTE 3: the calling thread must want access to the page given: this rule is
|
||||
set to prevent unintended read-aheads performed by ibuf routines, a situation
|
||||
which could result in a deadlock if the OS does not support asynchronous io. */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
buf_read_ahead_linear(
|
||||
/*==================*/
|
||||
/* out: number of page read requests issued */
|
||||
ulint space, /* in: space id */
|
||||
ulint zip_size,/* in: compressed page size in bytes, or 0 */
|
||||
ulint offset) /* in: page number of a page; NOTE: the current thread
|
||||
must want access to this page (see NOTE 3 above) */
|
||||
{
|
||||
ib_int64_t tablespace_version;
|
||||
buf_page_t* bpage;
|
||||
buf_frame_t* frame;
|
||||
buf_page_t* pred_bpage = NULL;
|
||||
ulint pred_offset;
|
||||
ulint succ_offset;
|
||||
ulint count;
|
||||
int asc_or_desc;
|
||||
ulint new_offset;
|
||||
ulint fail_count;
|
||||
ulint ibuf_mode;
|
||||
ulint low, high;
|
||||
ulint err;
|
||||
ulint i;
|
||||
const ulint buf_read_ahead_linear_area
|
||||
= BUF_READ_AHEAD_LINEAR_AREA;
|
||||
|
||||
if (!(srv_read_ahead & 2)) {
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (UNIV_UNLIKELY(srv_startup_is_before_trx_rollback_phase)) {
|
||||
/* No read-ahead to avoid thread deadlocks */
|
||||
return(0);
|
||||
}
|
||||
|
||||
low = (offset / buf_read_ahead_linear_area)
|
||||
* buf_read_ahead_linear_area;
|
||||
high = (offset / buf_read_ahead_linear_area + 1)
|
||||
* buf_read_ahead_linear_area;
|
||||
|
||||
if ((offset != low) && (offset != high - 1)) {
|
||||
/* This is not a border page of the area: return */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (ibuf_bitmap_page(zip_size, offset)
|
||||
|| trx_sys_hdr_page(space, offset)) {
|
||||
|
||||
/* If it is an ibuf bitmap page or trx sys hdr, we do
|
||||
no read-ahead, as that could break the ibuf page access
|
||||
order */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* Remember the tablespace version before we ask te tablespace size
|
||||
below: if DISCARD + IMPORT changes the actual .ibd file meanwhile, we
|
||||
do not try to read outside the bounds of the tablespace! */
|
||||
|
||||
tablespace_version = fil_space_get_version(space);
|
||||
|
||||
//buf_pool_mutex_enter();
|
||||
mutex_enter(&buf_pool_mutex);
|
||||
|
||||
if (high > fil_space_get_size(space)) {
|
||||
//buf_pool_mutex_exit();
|
||||
mutex_exit(&buf_pool_mutex);
|
||||
/* The area is not whole, return */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (buf_pool->n_pend_reads
|
||||
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
|
||||
//buf_pool_mutex_exit();
|
||||
mutex_exit(&buf_pool_mutex);
|
||||
|
||||
return(0);
|
||||
}
|
||||
mutex_exit(&buf_pool_mutex);
|
||||
|
||||
/* Check that almost all pages in the area have been accessed; if
|
||||
offset == low, the accesses must be in a descending order, otherwise,
|
||||
in an ascending order. */
|
||||
|
||||
asc_or_desc = 1;
|
||||
|
||||
if (offset == low) {
|
||||
asc_or_desc = -1;
|
||||
}
|
||||
|
||||
fail_count = 0;
|
||||
|
||||
rw_lock_s_lock(&page_hash_latch);
|
||||
for (i = low; i < high; i++) {
|
||||
bpage = buf_page_hash_get(space, i);
|
||||
|
||||
if ((bpage == NULL) || !buf_page_is_accessed(bpage)) {
|
||||
/* Not accessed */
|
||||
fail_count++;
|
||||
|
||||
} else if (pred_bpage
|
||||
&& (ut_ulint_cmp(
|
||||
buf_page_get_LRU_position(bpage),
|
||||
buf_page_get_LRU_position(pred_bpage))
|
||||
!= asc_or_desc)) {
|
||||
/* Accesses not in the right order */
|
||||
|
||||
fail_count++;
|
||||
pred_bpage = bpage;
|
||||
}
|
||||
}
|
||||
|
||||
if (fail_count > buf_read_ahead_linear_area
|
||||
* LINEAR_AREA_THRESHOLD_COEF) {
|
||||
/* Too many failures: return */
|
||||
|
||||
//buf_pool_mutex_exit();
|
||||
rw_lock_s_unlock(&page_hash_latch);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* If we got this far, we know that enough pages in the area have
|
||||
been accessed in the right order: linear read-ahead can be sensible */
|
||||
|
||||
bpage = buf_page_hash_get(space, offset);
|
||||
|
||||
if (bpage == NULL) {
|
||||
//buf_pool_mutex_exit();
|
||||
rw_lock_s_unlock(&page_hash_latch);
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
switch (buf_page_get_state(bpage)) {
|
||||
case BUF_BLOCK_ZIP_PAGE:
|
||||
frame = bpage->zip.data;
|
||||
break;
|
||||
case BUF_BLOCK_FILE_PAGE:
|
||||
frame = ((buf_block_t*) bpage)->frame;
|
||||
break;
|
||||
default:
|
||||
ut_error;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Read the natural predecessor and successor page addresses from
|
||||
the page; NOTE that because the calling thread may have an x-latch
|
||||
on the page, we do not acquire an s-latch on the page, this is to
|
||||
prevent deadlocks. Even if we read values which are nonsense, the
|
||||
algorithm will work. */
|
||||
|
||||
pred_offset = fil_page_get_prev(frame);
|
||||
succ_offset = fil_page_get_next(frame);
|
||||
|
||||
//buf_pool_mutex_exit();
|
||||
rw_lock_s_unlock(&page_hash_latch);
|
||||
|
||||
if ((offset == low) && (succ_offset == offset + 1)) {
|
||||
|
||||
/* This is ok, we can continue */
|
||||
new_offset = pred_offset;
|
||||
|
||||
} else if ((offset == high - 1) && (pred_offset == offset - 1)) {
|
||||
|
||||
/* This is ok, we can continue */
|
||||
new_offset = succ_offset;
|
||||
} else {
|
||||
/* Successor or predecessor not in the right order */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
low = (new_offset / buf_read_ahead_linear_area)
|
||||
* buf_read_ahead_linear_area;
|
||||
high = (new_offset / buf_read_ahead_linear_area + 1)
|
||||
* buf_read_ahead_linear_area;
|
||||
|
||||
if ((new_offset != low) && (new_offset != high - 1)) {
|
||||
/* This is not a border page of the area: return */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
if (high > fil_space_get_size(space)) {
|
||||
/* The area is not whole, return */
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/* If we got this far, read-ahead can be sensible: do it */
|
||||
|
||||
if (ibuf_inside()) {
|
||||
ibuf_mode = BUF_READ_IBUF_PAGES_ONLY;
|
||||
} else {
|
||||
ibuf_mode = BUF_READ_ANY_PAGE;
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
/* Since Windows XP seems to schedule the i/o handler thread
|
||||
very eagerly, and consequently it does not wait for the
|
||||
full read batch to be posted, we use special heuristics here */
|
||||
|
||||
os_aio_simulated_put_read_threads_to_sleep();
|
||||
|
||||
for (i = low; i < high; i++) {
|
||||
/* It is only sensible to do read-ahead in the non-sync
|
||||
aio mode: hence FALSE as the first parameter */
|
||||
|
||||
if (!ibuf_bitmap_page(zip_size, i)) {
|
||||
count += buf_read_page_low(
|
||||
&err, FALSE,
|
||||
ibuf_mode | OS_AIO_SIMULATED_WAKE_LATER,
|
||||
space, zip_size, FALSE, tablespace_version, i);
|
||||
if (err == DB_TABLESPACE_DELETED) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
" InnoDB: Warning: in"
|
||||
" linear readahead trying to access\n"
|
||||
"InnoDB: tablespace %lu page %lu,\n"
|
||||
"InnoDB: but the tablespace does not"
|
||||
" exist or is just being dropped.\n",
|
||||
(ulong) space, (ulong) i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* In simulated aio we wake the aio handler threads only after
|
||||
queuing all aio requests, in native aio the following call does
|
||||
nothing: */
|
||||
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
/* Flush pages from the end of the LRU list if necessary */
|
||||
buf_flush_free_margin(FALSE);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
if (buf_debug_prints && (count > 0)) {
|
||||
fprintf(stderr,
|
||||
"LINEAR read-ahead space %lu offset %lu pages %lu\n",
|
||||
(ulong) space, (ulong) offset, (ulong) count);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/* Read ahead is considered one I/O operation for the purpose of
|
||||
LRU policy decision. */
|
||||
buf_LRU_stat_inc_io();
|
||||
|
||||
++srv_read_ahead_seq;
|
||||
return(count);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Issues read requests for pages which the ibuf module wants to read in, in
|
||||
order to contract the insert buffer tree. Technically, this function is like
|
||||
a read-ahead function. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
buf_read_ibuf_merge_pages(
|
||||
/*======================*/
|
||||
ibool sync, /* in: TRUE if the caller
|
||||
wants this function to wait
|
||||
for the highest address page
|
||||
to get read in, before this
|
||||
function returns */
|
||||
const ulint* space_ids, /* in: array of space ids */
|
||||
const ib_int64_t* space_versions,/* in: the spaces must have
|
||||
this version number
|
||||
(timestamp), otherwise we
|
||||
discard the read; we use this
|
||||
to cancel reads if DISCARD +
|
||||
IMPORT may have changed the
|
||||
tablespace size */
|
||||
const ulint* page_nos, /* in: array of page numbers
|
||||
to read, with the highest page
|
||||
number the last in the
|
||||
array */
|
||||
ulint n_stored) /* in: number of elements
|
||||
in the arrays */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
ut_ad(!ibuf_inside());
|
||||
#ifdef UNIV_IBUF_DEBUG
|
||||
ut_a(n_stored < UNIV_PAGE_SIZE);
|
||||
#endif
|
||||
while (buf_pool->n_pend_reads
|
||||
> buf_pool->curr_size / BUF_READ_AHEAD_PEND_LIMIT) {
|
||||
os_thread_sleep(500000);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_stored; i++) {
|
||||
ulint zip_size = fil_space_get_zip_size(space_ids[i]);
|
||||
ulint err;
|
||||
|
||||
if (UNIV_UNLIKELY(zip_size == ULINT_UNDEFINED)) {
|
||||
|
||||
goto tablespace_deleted;
|
||||
}
|
||||
|
||||
buf_read_page_low(&err, sync && (i + 1 == n_stored),
|
||||
BUF_READ_ANY_PAGE, space_ids[i],
|
||||
zip_size, TRUE, space_versions[i],
|
||||
page_nos[i]);
|
||||
|
||||
if (UNIV_UNLIKELY(err == DB_TABLESPACE_DELETED)) {
|
||||
tablespace_deleted:
|
||||
/* We have deleted or are deleting the single-table
|
||||
tablespace: remove the entries for that page */
|
||||
|
||||
ibuf_merge_or_delete_for_page(NULL, space_ids[i],
|
||||
page_nos[i],
|
||||
zip_size, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
/* Flush pages from the end of the LRU list if necessary */
|
||||
buf_flush_free_margin(FALSE);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
if (buf_debug_prints) {
|
||||
fprintf(stderr,
|
||||
"Ibuf merge read-ahead space %lu pages %lu\n",
|
||||
(ulong) space_ids[0], (ulong) n_stored);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Issues read requests for pages which recovery wants to read in. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
buf_read_recv_pages(
|
||||
/*================*/
|
||||
ibool sync, /* in: TRUE if the caller
|
||||
wants this function to wait
|
||||
for the highest address page
|
||||
to get read in, before this
|
||||
function returns */
|
||||
ulint space, /* in: space id */
|
||||
ulint zip_size, /* in: compressed page size in
|
||||
bytes, or 0 */
|
||||
const ulint* page_nos, /* in: array of page numbers
|
||||
to read, with the highest page
|
||||
number the last in the
|
||||
array */
|
||||
ulint n_stored) /* in: number of page numbers
|
||||
in the array */
|
||||
{
|
||||
ib_int64_t tablespace_version;
|
||||
ulint count;
|
||||
ulint err;
|
||||
ulint i;
|
||||
|
||||
zip_size = fil_space_get_zip_size(space);
|
||||
tablespace_version = fil_space_get_version(space);
|
||||
|
||||
for (i = 0; i < n_stored; i++) {
|
||||
|
||||
count = 0;
|
||||
|
||||
os_aio_print_debug = FALSE;
|
||||
|
||||
while (buf_pool->n_pend_reads >= recv_n_pool_free_frames / 2) {
|
||||
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
os_thread_sleep(10000);
|
||||
|
||||
count++;
|
||||
|
||||
if (count > 5000) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: InnoDB has waited for"
|
||||
" 50 seconds for pending\n"
|
||||
"InnoDB: reads to the buffer pool to"
|
||||
" be finished.\n"
|
||||
"InnoDB: Number of pending reads %lu,"
|
||||
" pending pread calls %lu\n",
|
||||
(ulong) buf_pool->n_pend_reads,
|
||||
(ulong)os_file_n_pending_preads);
|
||||
|
||||
os_aio_print_debug = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
os_aio_print_debug = FALSE;
|
||||
|
||||
if ((i + 1 == n_stored) && sync) {
|
||||
buf_read_page_low(&err, TRUE, BUF_READ_ANY_PAGE, space,
|
||||
zip_size, TRUE, tablespace_version,
|
||||
page_nos[i]);
|
||||
} else {
|
||||
buf_read_page_low(&err, FALSE, BUF_READ_ANY_PAGE
|
||||
| OS_AIO_SIMULATED_WAKE_LATER,
|
||||
space, zip_size, TRUE,
|
||||
tablespace_version, page_nos[i]);
|
||||
}
|
||||
}
|
||||
|
||||
os_aio_simulated_wake_handler_threads();
|
||||
|
||||
/* Flush pages from the end of the LRU list if necessary */
|
||||
buf_flush_free_margin(FALSE);
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
if (buf_debug_prints) {
|
||||
fprintf(stderr,
|
||||
"Recovery applies read-ahead pages %lu\n",
|
||||
(ulong) n_stored);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
}
|
||||
758
storage/xtradb/data/data0data.c
Normal file
758
storage/xtradb/data/data0data.c
Normal file
|
|
@ -0,0 +1,758 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
SQL data field and tuple
|
||||
|
||||
Created 5/30/1994 Heikki Tuuri
|
||||
*************************************************************************/
|
||||
|
||||
#include "data0data.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "data0data.ic"
|
||||
#endif
|
||||
|
||||
#include "rem0rec.h"
|
||||
#include "rem0cmp.h"
|
||||
#include "page0page.h"
|
||||
#include "page0zip.h"
|
||||
#include "dict0dict.h"
|
||||
#include "btr0cur.h"
|
||||
|
||||
#include <ctype.h>
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/* data pointers of tuple fields are initialized to point here
|
||||
for error checking */
|
||||
UNIV_INTERN byte data_error;
|
||||
|
||||
# ifndef UNIV_DEBUG_VALGRIND
|
||||
/* this is used to fool the compiler in dtuple_validate */
|
||||
UNIV_INTERN ulint data_dummy;
|
||||
# endif /* !UNIV_DEBUG_VALGRIND */
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/*************************************************************************
|
||||
Tests if dfield data length and content is equal to the given. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dfield_data_is_binary_equal(
|
||||
/*========================*/
|
||||
/* out: TRUE if equal */
|
||||
const dfield_t* field, /* in: field */
|
||||
ulint len, /* in: data length or UNIV_SQL_NULL */
|
||||
const byte* data) /* in: data */
|
||||
{
|
||||
if (len != dfield_get_len(field)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
if (len == UNIV_SQL_NULL) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
if (0 != memcmp(dfield_get_data(field), data, len)) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Compare two data tuples, respecting the collation of character fields. */
|
||||
UNIV_INTERN
|
||||
int
|
||||
dtuple_coll_cmp(
|
||||
/*============*/
|
||||
/* out: 1, 0 , -1 if tuple1 is greater, equal,
|
||||
less, respectively, than tuple2 */
|
||||
const dtuple_t* tuple1, /* in: tuple 1 */
|
||||
const dtuple_t* tuple2) /* in: tuple 2 */
|
||||
{
|
||||
ulint n_fields;
|
||||
ulint i;
|
||||
|
||||
ut_ad(tuple1 && tuple2);
|
||||
ut_ad(tuple1->magic_n == DATA_TUPLE_MAGIC_N);
|
||||
ut_ad(tuple2->magic_n == DATA_TUPLE_MAGIC_N);
|
||||
ut_ad(dtuple_check_typed(tuple1));
|
||||
ut_ad(dtuple_check_typed(tuple2));
|
||||
|
||||
n_fields = dtuple_get_n_fields(tuple1);
|
||||
|
||||
if (n_fields != dtuple_get_n_fields(tuple2)) {
|
||||
|
||||
return(n_fields < dtuple_get_n_fields(tuple2) ? -1 : 1);
|
||||
}
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
int cmp;
|
||||
const dfield_t* field1 = dtuple_get_nth_field(tuple1, i);
|
||||
const dfield_t* field2 = dtuple_get_nth_field(tuple2, i);
|
||||
|
||||
cmp = cmp_dfield_dfield(field1, field2);
|
||||
|
||||
if (cmp) {
|
||||
return(cmp);
|
||||
}
|
||||
}
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Sets number of fields used in a tuple. Normally this is set in
|
||||
dtuple_create, but if you want later to set it smaller, you can use this. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dtuple_set_n_fields(
|
||||
/*================*/
|
||||
dtuple_t* tuple, /* in: tuple */
|
||||
ulint n_fields) /* in: number of fields */
|
||||
{
|
||||
ut_ad(tuple);
|
||||
|
||||
tuple->n_fields = n_fields;
|
||||
tuple->n_fields_cmp = n_fields;
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Checks that a data field is typed. */
|
||||
static
|
||||
ibool
|
||||
dfield_check_typed_no_assert(
|
||||
/*=========================*/
|
||||
/* out: TRUE if ok */
|
||||
const dfield_t* field) /* in: data field */
|
||||
{
|
||||
if (dfield_get_type(field)->mtype > DATA_MYSQL
|
||||
|| dfield_get_type(field)->mtype < DATA_VARCHAR) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: data field type %lu, len %lu\n",
|
||||
(ulong) dfield_get_type(field)->mtype,
|
||||
(ulong) dfield_get_len(field));
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Checks that a data tuple is typed. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dtuple_check_typed_no_assert(
|
||||
/*=========================*/
|
||||
/* out: TRUE if ok */
|
||||
const dtuple_t* tuple) /* in: tuple */
|
||||
{
|
||||
const dfield_t* field;
|
||||
ulint i;
|
||||
|
||||
if (dtuple_get_n_fields(tuple) > REC_MAX_N_FIELDS) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: index entry has %lu fields\n",
|
||||
(ulong) dtuple_get_n_fields(tuple));
|
||||
dump:
|
||||
fputs("InnoDB: Tuple contents: ", stderr);
|
||||
dtuple_print(stderr, tuple);
|
||||
putc('\n', stderr);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
|
||||
|
||||
field = dtuple_get_nth_field(tuple, i);
|
||||
|
||||
if (!dfield_check_typed_no_assert(field)) {
|
||||
goto dump;
|
||||
}
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Checks that a data field is typed. Asserts an error if not. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dfield_check_typed(
|
||||
/*===============*/
|
||||
/* out: TRUE if ok */
|
||||
const dfield_t* field) /* in: data field */
|
||||
{
|
||||
if (dfield_get_type(field)->mtype > DATA_MYSQL
|
||||
|| dfield_get_type(field)->mtype < DATA_VARCHAR) {
|
||||
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: data field type %lu, len %lu\n",
|
||||
(ulong) dfield_get_type(field)->mtype,
|
||||
(ulong) dfield_get_len(field));
|
||||
|
||||
ut_error;
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
Checks that a data tuple is typed. Asserts an error if not. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dtuple_check_typed(
|
||||
/*===============*/
|
||||
/* out: TRUE if ok */
|
||||
const dtuple_t* tuple) /* in: tuple */
|
||||
{
|
||||
const dfield_t* field;
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < dtuple_get_n_fields(tuple); i++) {
|
||||
|
||||
field = dtuple_get_nth_field(tuple, i);
|
||||
|
||||
ut_a(dfield_check_typed(field));
|
||||
}
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
/**************************************************************
|
||||
Validates the consistency of a tuple which must be complete, i.e,
|
||||
all fields must have been set. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dtuple_validate(
|
||||
/*============*/
|
||||
/* out: TRUE if ok */
|
||||
const dtuple_t* tuple) /* in: tuple */
|
||||
{
|
||||
const dfield_t* field;
|
||||
ulint n_fields;
|
||||
ulint len;
|
||||
ulint i;
|
||||
|
||||
ut_ad(tuple->magic_n == DATA_TUPLE_MAGIC_N);
|
||||
|
||||
n_fields = dtuple_get_n_fields(tuple);
|
||||
|
||||
/* We dereference all the data of each field to test
|
||||
for memory traps */
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
|
||||
field = dtuple_get_nth_field(tuple, i);
|
||||
len = dfield_get_len(field);
|
||||
|
||||
if (!dfield_is_null(field)) {
|
||||
|
||||
const byte* data = dfield_get_data(field);
|
||||
#ifndef UNIV_DEBUG_VALGRIND
|
||||
ulint j;
|
||||
|
||||
for (j = 0; j < len; j++) {
|
||||
|
||||
data_dummy += *data; /* fool the compiler not
|
||||
to optimize out this
|
||||
code */
|
||||
data++;
|
||||
}
|
||||
#endif /* !UNIV_DEBUG_VALGRIND */
|
||||
|
||||
UNIV_MEM_ASSERT_RW(data, len);
|
||||
}
|
||||
}
|
||||
|
||||
ut_a(dtuple_check_typed(tuple));
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
/*****************************************************************
|
||||
Pretty prints a dfield value according to its data type. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dfield_print(
|
||||
/*=========*/
|
||||
const dfield_t* dfield) /* in: dfield */
|
||||
{
|
||||
const byte* data;
|
||||
ulint len;
|
||||
ulint i;
|
||||
|
||||
len = dfield_get_len(dfield);
|
||||
data = dfield_get_data(dfield);
|
||||
|
||||
if (dfield_is_null(dfield)) {
|
||||
fputs("NULL", stderr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
switch (dtype_get_mtype(dfield_get_type(dfield))) {
|
||||
case DATA_CHAR:
|
||||
case DATA_VARCHAR:
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = *data++;
|
||||
putc(isprint(c) ? c : ' ', stderr);
|
||||
}
|
||||
|
||||
if (dfield_is_ext(dfield)) {
|
||||
fputs("(external)", stderr);
|
||||
}
|
||||
break;
|
||||
case DATA_INT:
|
||||
ut_a(len == 4); /* only works for 32-bit integers */
|
||||
fprintf(stderr, "%d", (int)mach_read_from_4(data));
|
||||
break;
|
||||
default:
|
||||
ut_error;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Pretty prints a dfield value according to its data type. Also the hex string
|
||||
is printed if a string contains non-printable characters. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dfield_print_also_hex(
|
||||
/*==================*/
|
||||
const dfield_t* dfield) /* in: dfield */
|
||||
{
|
||||
const byte* data;
|
||||
ulint len;
|
||||
ulint prtype;
|
||||
ulint i;
|
||||
ibool print_also_hex;
|
||||
|
||||
len = dfield_get_len(dfield);
|
||||
data = dfield_get_data(dfield);
|
||||
|
||||
if (dfield_is_null(dfield)) {
|
||||
fputs("NULL", stderr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
prtype = dtype_get_prtype(dfield_get_type(dfield));
|
||||
|
||||
switch (dtype_get_mtype(dfield_get_type(dfield))) {
|
||||
dulint id;
|
||||
case DATA_INT:
|
||||
switch (len) {
|
||||
ulint val;
|
||||
case 1:
|
||||
val = mach_read_from_1(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x80;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
val = mach_read_from_2(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x8000;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
break;
|
||||
|
||||
case 3:
|
||||
val = mach_read_from_3(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x800000;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
break;
|
||||
|
||||
case 4:
|
||||
val = mach_read_from_4(data);
|
||||
|
||||
if (!(prtype & DATA_UNSIGNED)) {
|
||||
val &= ~0x80000000;
|
||||
fprintf(stderr, "%ld", (long) val);
|
||||
} else {
|
||||
fprintf(stderr, "%lu", (ulong) val);
|
||||
}
|
||||
break;
|
||||
|
||||
case 6:
|
||||
id = mach_read_from_6(data);
|
||||
fprintf(stderr, "{%lu %lu}",
|
||||
ut_dulint_get_high(id),
|
||||
ut_dulint_get_low(id));
|
||||
break;
|
||||
|
||||
case 7:
|
||||
id = mach_read_from_7(data);
|
||||
fprintf(stderr, "{%lu %lu}",
|
||||
ut_dulint_get_high(id),
|
||||
ut_dulint_get_low(id));
|
||||
break;
|
||||
case 8:
|
||||
id = mach_read_from_8(data);
|
||||
fprintf(stderr, "{%lu %lu}",
|
||||
ut_dulint_get_high(id),
|
||||
ut_dulint_get_low(id));
|
||||
break;
|
||||
default:
|
||||
goto print_hex;
|
||||
}
|
||||
break;
|
||||
|
||||
case DATA_SYS:
|
||||
switch (prtype & DATA_SYS_PRTYPE_MASK) {
|
||||
case DATA_TRX_ID:
|
||||
id = mach_read_from_6(data);
|
||||
|
||||
fprintf(stderr, "trx_id " TRX_ID_FMT,
|
||||
TRX_ID_PREP_PRINTF(id));
|
||||
break;
|
||||
|
||||
case DATA_ROLL_PTR:
|
||||
id = mach_read_from_7(data);
|
||||
|
||||
fprintf(stderr, "roll_ptr {%lu %lu}",
|
||||
ut_dulint_get_high(id), ut_dulint_get_low(id));
|
||||
break;
|
||||
|
||||
case DATA_ROW_ID:
|
||||
id = mach_read_from_6(data);
|
||||
|
||||
fprintf(stderr, "row_id {%lu %lu}",
|
||||
ut_dulint_get_high(id), ut_dulint_get_low(id));
|
||||
break;
|
||||
|
||||
default:
|
||||
id = mach_dulint_read_compressed(data);
|
||||
|
||||
fprintf(stderr, "mix_id {%lu %lu}",
|
||||
ut_dulint_get_high(id), ut_dulint_get_low(id));
|
||||
}
|
||||
break;
|
||||
|
||||
case DATA_CHAR:
|
||||
case DATA_VARCHAR:
|
||||
print_also_hex = FALSE;
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
int c = *data++;
|
||||
|
||||
if (!isprint(c)) {
|
||||
print_also_hex = TRUE;
|
||||
|
||||
fprintf(stderr, "\\x%02x", (unsigned char) c);
|
||||
} else {
|
||||
putc(c, stderr);
|
||||
}
|
||||
}
|
||||
|
||||
if (dfield_is_ext(dfield)) {
|
||||
fputs("(external)", stderr);
|
||||
}
|
||||
|
||||
if (!print_also_hex) {
|
||||
break;
|
||||
}
|
||||
|
||||
data = dfield_get_data(dfield);
|
||||
/* fall through */
|
||||
|
||||
case DATA_BINARY:
|
||||
default:
|
||||
print_hex:
|
||||
fputs(" Hex: ",stderr);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
fprintf(stderr, "%02lx", (ulint) *data++);
|
||||
}
|
||||
|
||||
if (dfield_is_ext(dfield)) {
|
||||
fputs("(external)", stderr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Print a dfield value using ut_print_buf. */
|
||||
static
|
||||
void
|
||||
dfield_print_raw(
|
||||
/*=============*/
|
||||
FILE* f, /* in: output stream */
|
||||
const dfield_t* dfield) /* in: dfield */
|
||||
{
|
||||
ulint len = dfield_get_len(dfield);
|
||||
if (!dfield_is_null(dfield)) {
|
||||
ulint print_len = ut_min(len, 1000);
|
||||
ut_print_buf(f, dfield_get_data(dfield), print_len);
|
||||
if (len != print_len) {
|
||||
fprintf(f, "(total %lu bytes%s)",
|
||||
(ulong) len,
|
||||
dfield_is_ext(dfield) ? ", external" : "");
|
||||
}
|
||||
} else {
|
||||
fputs(" SQL NULL", f);
|
||||
}
|
||||
}
|
||||
|
||||
/**************************************************************
|
||||
The following function prints the contents of a tuple. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dtuple_print(
|
||||
/*=========*/
|
||||
FILE* f, /* in: output stream */
|
||||
const dtuple_t* tuple) /* in: tuple */
|
||||
{
|
||||
ulint n_fields;
|
||||
ulint i;
|
||||
|
||||
n_fields = dtuple_get_n_fields(tuple);
|
||||
|
||||
fprintf(f, "DATA TUPLE: %lu fields;\n", (ulong) n_fields);
|
||||
|
||||
for (i = 0; i < n_fields; i++) {
|
||||
fprintf(f, " %lu:", (ulong) i);
|
||||
|
||||
dfield_print_raw(f, dtuple_get_nth_field(tuple, i));
|
||||
|
||||
putc(';', f);
|
||||
putc('\n', f);
|
||||
}
|
||||
|
||||
ut_ad(dtuple_validate(tuple));
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
Moves parts of long fields in entry to the big record vector so that
|
||||
the size of tuple drops below the maximum record size allowed in the
|
||||
database. Moves data only from those fields which are not necessary
|
||||
to determine uniquely the insertion place of the tuple in the index. */
|
||||
UNIV_INTERN
|
||||
big_rec_t*
|
||||
dtuple_convert_big_rec(
|
||||
/*===================*/
|
||||
/* out, own: created big record vector,
|
||||
NULL if we are not able to shorten
|
||||
the entry enough, i.e., if there are
|
||||
too many fixed-length or short fields
|
||||
in entry or the index is clustered */
|
||||
dict_index_t* index, /* in: index */
|
||||
dtuple_t* entry, /* in/out: index entry */
|
||||
ulint* n_ext) /* in/out: number of
|
||||
externally stored columns */
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
big_rec_t* vector;
|
||||
dfield_t* dfield;
|
||||
dict_field_t* ifield;
|
||||
ulint size;
|
||||
ulint n_fields;
|
||||
ulint local_len;
|
||||
ulint local_prefix_len;
|
||||
|
||||
if (UNIV_UNLIKELY(!dict_index_is_clust(index))) {
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
if (dict_table_get_format(index->table) < DICT_TF_FORMAT_ZIP) {
|
||||
/* up to MySQL 5.1: store a 768-byte prefix locally */
|
||||
local_len = BTR_EXTERN_FIELD_REF_SIZE + DICT_MAX_INDEX_COL_LEN;
|
||||
} else {
|
||||
/* new-format table: do not store any BLOB prefix locally */
|
||||
local_len = BTR_EXTERN_FIELD_REF_SIZE;
|
||||
}
|
||||
|
||||
ut_a(dtuple_check_typed_no_assert(entry));
|
||||
|
||||
size = rec_get_converted_size(index, entry, *n_ext);
|
||||
|
||||
if (UNIV_UNLIKELY(size > 1000000000)) {
|
||||
fprintf(stderr,
|
||||
"InnoDB: Warning: tuple size very big: %lu\n",
|
||||
(ulong) size);
|
||||
fputs("InnoDB: Tuple contents: ", stderr);
|
||||
dtuple_print(stderr, entry);
|
||||
putc('\n', stderr);
|
||||
}
|
||||
|
||||
heap = mem_heap_create(size + dtuple_get_n_fields(entry)
|
||||
* sizeof(big_rec_field_t) + 1000);
|
||||
|
||||
vector = mem_heap_alloc(heap, sizeof(big_rec_t));
|
||||
|
||||
vector->heap = heap;
|
||||
vector->fields = mem_heap_alloc(heap, dtuple_get_n_fields(entry)
|
||||
* sizeof(big_rec_field_t));
|
||||
|
||||
/* Decide which fields to shorten: the algorithm is to look for
|
||||
a variable-length field that yields the biggest savings when
|
||||
stored externally */
|
||||
|
||||
n_fields = 0;
|
||||
|
||||
while (page_zip_rec_needs_ext(rec_get_converted_size(index, entry,
|
||||
*n_ext),
|
||||
dict_table_is_comp(index->table),
|
||||
dict_index_get_n_fields(index),
|
||||
dict_table_zip_size(index->table))) {
|
||||
ulint i;
|
||||
ulint longest = 0;
|
||||
ulint longest_i = ULINT_MAX;
|
||||
byte* data;
|
||||
big_rec_field_t* b;
|
||||
|
||||
for (i = dict_index_get_n_unique_in_tree(index);
|
||||
i < dtuple_get_n_fields(entry); i++) {
|
||||
ulint savings;
|
||||
|
||||
dfield = dtuple_get_nth_field(entry, i);
|
||||
ifield = dict_index_get_nth_field(index, i);
|
||||
|
||||
/* Skip fixed-length, NULL, externally stored,
|
||||
or short columns */
|
||||
|
||||
if (ifield->fixed_len
|
||||
|| dfield_is_null(dfield)
|
||||
|| dfield_is_ext(dfield)
|
||||
|| dfield_get_len(dfield) <= local_len
|
||||
|| dfield_get_len(dfield)
|
||||
<= BTR_EXTERN_FIELD_REF_SIZE * 2) {
|
||||
goto skip_field;
|
||||
}
|
||||
|
||||
savings = dfield_get_len(dfield) - local_len;
|
||||
|
||||
/* Check that there would be savings */
|
||||
if (longest >= savings) {
|
||||
goto skip_field;
|
||||
}
|
||||
|
||||
longest_i = i;
|
||||
longest = savings;
|
||||
|
||||
skip_field:
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!longest) {
|
||||
/* Cannot shorten more */
|
||||
|
||||
mem_heap_free(heap);
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* Move data from field longest_i to big rec vector.
|
||||
|
||||
We store the first bytes locally to the record. Then
|
||||
we can calculate all ordering fields in all indexes
|
||||
from locally stored data. */
|
||||
|
||||
dfield = dtuple_get_nth_field(entry, longest_i);
|
||||
ifield = dict_index_get_nth_field(index, longest_i);
|
||||
local_prefix_len = local_len - BTR_EXTERN_FIELD_REF_SIZE;
|
||||
|
||||
b = &vector->fields[n_fields];
|
||||
b->field_no = longest_i;
|
||||
b->len = dfield_get_len(dfield) - local_prefix_len;
|
||||
b->data = (char*) dfield_get_data(dfield) + local_prefix_len;
|
||||
|
||||
/* Allocate the locally stored part of the column. */
|
||||
data = mem_heap_alloc(heap, local_len);
|
||||
|
||||
/* Copy the local prefix. */
|
||||
memcpy(data, dfield_get_data(dfield), local_prefix_len);
|
||||
/* Clear the extern field reference (BLOB pointer). */
|
||||
memset(data + local_prefix_len, 0, BTR_EXTERN_FIELD_REF_SIZE);
|
||||
#if 0
|
||||
/* The following would fail the Valgrind checks in
|
||||
page_cur_insert_rec_low() and page_cur_insert_rec_zip().
|
||||
The BLOB pointers in the record will be initialized after
|
||||
the record and the BLOBs have been written. */
|
||||
UNIV_MEM_ALLOC(data + local_prefix_len,
|
||||
BTR_EXTERN_FIELD_REF_SIZE);
|
||||
#endif
|
||||
|
||||
dfield_set_data(dfield, data, local_len);
|
||||
dfield_set_ext(dfield);
|
||||
|
||||
n_fields++;
|
||||
(*n_ext)++;
|
||||
ut_ad(n_fields < dtuple_get_n_fields(entry));
|
||||
}
|
||||
|
||||
vector->n_fields = n_fields;
|
||||
return(vector);
|
||||
}
|
||||
|
||||
/******************************************************************
|
||||
Puts back to entry the data stored in vector. Note that to ensure the
|
||||
fields in entry can accommodate the data, vector must have been created
|
||||
from entry with dtuple_convert_big_rec. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dtuple_convert_back_big_rec(
|
||||
/*========================*/
|
||||
dict_index_t* index __attribute__((unused)), /* in: index */
|
||||
dtuple_t* entry, /* in: entry whose data was put to vector */
|
||||
big_rec_t* vector) /* in, own: big rec vector; it is
|
||||
freed in this function */
|
||||
{
|
||||
big_rec_field_t* b = vector->fields;
|
||||
const big_rec_field_t* const end = b + vector->n_fields;
|
||||
|
||||
for (; b < end; b++) {
|
||||
dfield_t* dfield;
|
||||
ulint local_len;
|
||||
|
||||
dfield = dtuple_get_nth_field(entry, b->field_no);
|
||||
local_len = dfield_get_len(dfield);
|
||||
|
||||
ut_ad(dfield_is_ext(dfield));
|
||||
ut_ad(local_len >= BTR_EXTERN_FIELD_REF_SIZE);
|
||||
|
||||
local_len -= BTR_EXTERN_FIELD_REF_SIZE;
|
||||
|
||||
ut_ad(local_len <= DICT_MAX_INDEX_COL_LEN);
|
||||
|
||||
dfield_set_data(dfield,
|
||||
(char*) b->data - local_len,
|
||||
b->len + local_len);
|
||||
}
|
||||
|
||||
mem_heap_free(vector->heap);
|
||||
}
|
||||
300
storage/xtradb/data/data0type.c
Normal file
300
storage/xtradb/data/data0type.c
Normal file
|
|
@ -0,0 +1,300 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
Data types
|
||||
|
||||
Created 1/16/1996 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "data0type.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "data0type.ic"
|
||||
#endif
|
||||
|
||||
/**********************************************************************
|
||||
This function is used to find the storage length in bytes of the first n
|
||||
characters for prefix indexes using a multibyte character set. The function
|
||||
finds charset information and returns length of prefix_len characters in the
|
||||
index field in bytes.
|
||||
|
||||
NOTE: the prototype of this function is copied from ha_innodb.cc! If you change
|
||||
this function, you MUST change also the prototype here! */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
innobase_get_at_most_n_mbchars(
|
||||
/*===========================*/
|
||||
/* out: number of bytes occupied by the first
|
||||
n characters */
|
||||
ulint charset_id, /* in: character set id */
|
||||
ulint prefix_len, /* in: prefix length in bytes of the index
|
||||
(this has to be divided by mbmaxlen to get the
|
||||
number of CHARACTERS n in the prefix) */
|
||||
ulint data_len, /* in: length of the string in bytes */
|
||||
const char* str); /* in: character string */
|
||||
|
||||
/* At the database startup we store the default-charset collation number of
|
||||
this MySQL installation to this global variable. If we have < 4.1.2 format
|
||||
column definitions, or records in the insert buffer, we use this
|
||||
charset-collation code for them. */
|
||||
|
||||
UNIV_INTERN ulint data_mysql_default_charset_coll;
|
||||
|
||||
/*************************************************************************
|
||||
Determine how many bytes the first n characters of the given string occupy.
|
||||
If the string is shorter than n characters, returns the number of bytes
|
||||
the characters in the string occupy. */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
dtype_get_at_most_n_mbchars(
|
||||
/*========================*/
|
||||
/* out: length of the prefix,
|
||||
in bytes */
|
||||
ulint prtype, /* in: precise type */
|
||||
ulint mbminlen, /* in: minimum length of a
|
||||
multi-byte character */
|
||||
ulint mbmaxlen, /* in: maximum length of a
|
||||
multi-byte character */
|
||||
ulint prefix_len, /* in: length of the requested
|
||||
prefix, in characters, multiplied by
|
||||
dtype_get_mbmaxlen(dtype) */
|
||||
ulint data_len, /* in: length of str (in bytes) */
|
||||
const char* str) /* in: the string whose prefix
|
||||
length is being determined */
|
||||
{
|
||||
#ifndef UNIV_HOTBACKUP
|
||||
ut_a(data_len != UNIV_SQL_NULL);
|
||||
ut_ad(!mbmaxlen || !(prefix_len % mbmaxlen));
|
||||
|
||||
if (mbminlen != mbmaxlen) {
|
||||
ut_a(!(prefix_len % mbmaxlen));
|
||||
return(innobase_get_at_most_n_mbchars(
|
||||
dtype_get_charset_coll(prtype),
|
||||
prefix_len, data_len, str));
|
||||
}
|
||||
|
||||
if (prefix_len < data_len) {
|
||||
|
||||
return(prefix_len);
|
||||
|
||||
}
|
||||
|
||||
return(data_len);
|
||||
#else /* UNIV_HOTBACKUP */
|
||||
/* This function depends on MySQL code that is not included in
|
||||
InnoDB Hot Backup builds. Besides, this function should never
|
||||
be called in InnoDB Hot Backup. */
|
||||
ut_error;
|
||||
#endif /* UNIV_HOTBACKUP */
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a data main type is a string type. Also a BLOB is considered a
|
||||
string type. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dtype_is_string_type(
|
||||
/*=================*/
|
||||
/* out: TRUE if string type */
|
||||
ulint mtype) /* in: InnoDB main data type code: DATA_CHAR, ... */
|
||||
{
|
||||
if (mtype <= DATA_BLOB
|
||||
|| mtype == DATA_MYSQL
|
||||
|| mtype == DATA_VARMYSQL) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a type is a binary string type. Note that for tables created with
|
||||
< 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column. For
|
||||
those DATA_BLOB columns this function currently returns FALSE. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dtype_is_binary_string_type(
|
||||
/*========================*/
|
||||
/* out: TRUE if binary string type */
|
||||
ulint mtype, /* in: main data type */
|
||||
ulint prtype) /* in: precise type */
|
||||
{
|
||||
if ((mtype == DATA_FIXBINARY)
|
||||
|| (mtype == DATA_BINARY)
|
||||
|| (mtype == DATA_BLOB && (prtype & DATA_BINARY_TYPE))) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Checks if a type is a non-binary string type. That is, dtype_is_string_type is
|
||||
TRUE and dtype_is_binary_string_type is FALSE. Note that for tables created
|
||||
with < 4.0.14, we do not know if a DATA_BLOB column is a BLOB or a TEXT column.
|
||||
For those DATA_BLOB columns this function currently returns TRUE. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dtype_is_non_binary_string_type(
|
||||
/*============================*/
|
||||
/* out: TRUE if non-binary string type */
|
||||
ulint mtype, /* in: main data type */
|
||||
ulint prtype) /* in: precise type */
|
||||
{
|
||||
if (dtype_is_string_type(mtype) == TRUE
|
||||
&& dtype_is_binary_string_type(mtype, prtype) == FALSE) {
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Forms a precise type from the < 4.1.2 format precise type plus the
|
||||
charset-collation code. */
|
||||
UNIV_INTERN
|
||||
ulint
|
||||
dtype_form_prtype(
|
||||
/*==============*/
|
||||
ulint old_prtype, /* in: the MySQL type code and the flags
|
||||
DATA_BINARY_TYPE etc. */
|
||||
ulint charset_coll) /* in: MySQL charset-collation code */
|
||||
{
|
||||
ut_a(old_prtype < 256 * 256);
|
||||
ut_a(charset_coll < 256);
|
||||
|
||||
return(old_prtype + (charset_coll << 16));
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Validates a data type structure. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
dtype_validate(
|
||||
/*===========*/
|
||||
/* out: TRUE if ok */
|
||||
const dtype_t* type) /* in: type struct to validate */
|
||||
{
|
||||
ut_a(type);
|
||||
ut_a(type->mtype >= DATA_VARCHAR);
|
||||
ut_a(type->mtype <= DATA_MYSQL);
|
||||
|
||||
if (type->mtype == DATA_SYS) {
|
||||
ut_a((type->prtype & DATA_MYSQL_TYPE_MASK) < DATA_N_SYS_COLS);
|
||||
}
|
||||
|
||||
ut_a(type->mbminlen <= type->mbmaxlen);
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*************************************************************************
|
||||
Prints a data type structure. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dtype_print(
|
||||
/*========*/
|
||||
const dtype_t* type) /* in: type */
|
||||
{
|
||||
ulint mtype;
|
||||
ulint prtype;
|
||||
ulint len;
|
||||
|
||||
ut_a(type);
|
||||
|
||||
mtype = type->mtype;
|
||||
prtype = type->prtype;
|
||||
|
||||
switch (mtype) {
|
||||
case DATA_VARCHAR:
|
||||
fputs("DATA_VARCHAR", stderr);
|
||||
break;
|
||||
|
||||
case DATA_CHAR:
|
||||
fputs("DATA_CHAR", stderr);
|
||||
break;
|
||||
|
||||
case DATA_BINARY:
|
||||
fputs("DATA_BINARY", stderr);
|
||||
break;
|
||||
|
||||
case DATA_FIXBINARY:
|
||||
fputs("DATA_FIXBINARY", stderr);
|
||||
break;
|
||||
|
||||
case DATA_BLOB:
|
||||
fputs("DATA_BLOB", stderr);
|
||||
break;
|
||||
|
||||
case DATA_INT:
|
||||
fputs("DATA_INT", stderr);
|
||||
break;
|
||||
|
||||
case DATA_MYSQL:
|
||||
fputs("DATA_MYSQL", stderr);
|
||||
break;
|
||||
|
||||
case DATA_SYS:
|
||||
fputs("DATA_SYS", stderr);
|
||||
break;
|
||||
|
||||
default:
|
||||
fprintf(stderr, "type %lu", (ulong) mtype);
|
||||
break;
|
||||
}
|
||||
|
||||
len = type->len;
|
||||
|
||||
if ((type->mtype == DATA_SYS)
|
||||
|| (type->mtype == DATA_VARCHAR)
|
||||
|| (type->mtype == DATA_CHAR)) {
|
||||
putc(' ', stderr);
|
||||
if (prtype == DATA_ROW_ID) {
|
||||
fputs("DATA_ROW_ID", stderr);
|
||||
len = DATA_ROW_ID_LEN;
|
||||
} else if (prtype == DATA_ROLL_PTR) {
|
||||
fputs("DATA_ROLL_PTR", stderr);
|
||||
len = DATA_ROLL_PTR_LEN;
|
||||
} else if (prtype == DATA_TRX_ID) {
|
||||
fputs("DATA_TRX_ID", stderr);
|
||||
len = DATA_TRX_ID_LEN;
|
||||
} else if (prtype == DATA_ENGLISH) {
|
||||
fputs("DATA_ENGLISH", stderr);
|
||||
} else {
|
||||
fprintf(stderr, "prtype %lu", (ulong) prtype);
|
||||
}
|
||||
} else {
|
||||
if (prtype & DATA_UNSIGNED) {
|
||||
fputs(" DATA_UNSIGNED", stderr);
|
||||
}
|
||||
|
||||
if (prtype & DATA_BINARY_TYPE) {
|
||||
fputs(" DATA_BINARY_TYPE", stderr);
|
||||
}
|
||||
|
||||
if (prtype & DATA_NOT_NULL) {
|
||||
fputs(" DATA_NOT_NULL", stderr);
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, " len %lu", (ulong) len);
|
||||
}
|
||||
466
storage/xtradb/dict/dict0boot.c
Normal file
466
storage/xtradb/dict/dict0boot.c
Normal file
|
|
@ -0,0 +1,466 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
Data dictionary creation and booting
|
||||
|
||||
Created 4/18/1996 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "dict0boot.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "dict0boot.ic"
|
||||
#endif
|
||||
|
||||
#include "dict0crea.h"
|
||||
#include "btr0btr.h"
|
||||
#include "dict0load.h"
|
||||
#include "dict0load.h"
|
||||
#include "trx0trx.h"
|
||||
#include "srv0srv.h"
|
||||
#include "ibuf0ibuf.h"
|
||||
#include "buf0flu.h"
|
||||
#include "log0recv.h"
|
||||
#include "os0file.h"
|
||||
|
||||
/**************************************************************************
|
||||
Gets a pointer to the dictionary header and x-latches its page. */
|
||||
UNIV_INTERN
|
||||
dict_hdr_t*
|
||||
dict_hdr_get(
|
||||
/*=========*/
|
||||
/* out: pointer to the dictionary header,
|
||||
page x-latched */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
buf_block_t* block;
|
||||
dict_hdr_t* header;
|
||||
|
||||
block = buf_page_get(DICT_HDR_SPACE, 0, DICT_HDR_PAGE_NO,
|
||||
RW_X_LATCH, mtr);
|
||||
header = DICT_HDR + buf_block_get_frame(block);
|
||||
|
||||
buf_block_dbg_add_level(block, SYNC_DICT_HEADER);
|
||||
|
||||
return(header);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Returns a new table, index, or tree id. */
|
||||
UNIV_INTERN
|
||||
dulint
|
||||
dict_hdr_get_new_id(
|
||||
/*================*/
|
||||
/* out: the new id */
|
||||
ulint type) /* in: DICT_HDR_ROW_ID, ... */
|
||||
{
|
||||
dict_hdr_t* dict_hdr;
|
||||
dulint id;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad((type == DICT_HDR_TABLE_ID) || (type == DICT_HDR_INDEX_ID));
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
dict_hdr = dict_hdr_get(&mtr);
|
||||
|
||||
id = mtr_read_dulint(dict_hdr + type, &mtr);
|
||||
id = ut_dulint_add(id, 1);
|
||||
|
||||
mlog_write_dulint(dict_hdr + type, id, &mtr);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
return(id);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Writes the current value of the row id counter to the dictionary header file
|
||||
page. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_hdr_flush_row_id(void)
|
||||
/*=======================*/
|
||||
{
|
||||
dict_hdr_t* dict_hdr;
|
||||
dulint id;
|
||||
mtr_t mtr;
|
||||
|
||||
ut_ad(mutex_own(&(dict_sys->mutex)));
|
||||
|
||||
id = dict_sys->row_id;
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
dict_hdr = dict_hdr_get(&mtr);
|
||||
|
||||
mlog_write_dulint(dict_hdr + DICT_HDR_ROW_ID, id, &mtr);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Creates the file page for the dictionary header. This function is
|
||||
called only at the database creation. */
|
||||
static
|
||||
ibool
|
||||
dict_hdr_create(
|
||||
/*============*/
|
||||
/* out: TRUE if succeed */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
buf_block_t* block;
|
||||
dict_hdr_t* dict_header;
|
||||
ulint root_page_no;
|
||||
|
||||
ut_ad(mtr);
|
||||
|
||||
/* Create the dictionary header file block in a new, allocated file
|
||||
segment in the system tablespace */
|
||||
block = fseg_create(DICT_HDR_SPACE, 0,
|
||||
DICT_HDR + DICT_HDR_FSEG_HEADER, mtr);
|
||||
|
||||
ut_a(DICT_HDR_PAGE_NO == buf_block_get_page_no(block));
|
||||
|
||||
dict_header = dict_hdr_get(mtr);
|
||||
|
||||
/* Start counting row, table, index, and tree ids from
|
||||
DICT_HDR_FIRST_ID */
|
||||
mlog_write_dulint(dict_header + DICT_HDR_ROW_ID,
|
||||
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
|
||||
|
||||
mlog_write_dulint(dict_header + DICT_HDR_TABLE_ID,
|
||||
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
|
||||
|
||||
mlog_write_dulint(dict_header + DICT_HDR_INDEX_ID,
|
||||
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
|
||||
|
||||
/* Obsolete, but we must initialize it to 0 anyway. */
|
||||
mlog_write_dulint(dict_header + DICT_HDR_MIX_ID,
|
||||
ut_dulint_create(0, DICT_HDR_FIRST_ID), mtr);
|
||||
|
||||
/* Create the B-tree roots for the clustered indexes of the basic
|
||||
system tables */
|
||||
|
||||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
DICT_HDR_SPACE, 0, DICT_TABLES_ID,
|
||||
srv_sys->dummy_ind1, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
mlog_write_ulint(dict_header + DICT_HDR_TABLES, root_page_no,
|
||||
MLOG_4BYTES, mtr);
|
||||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_UNIQUE, DICT_HDR_SPACE, 0,
|
||||
DICT_TABLE_IDS_ID,
|
||||
srv_sys->dummy_ind1, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
mlog_write_ulint(dict_header + DICT_HDR_TABLE_IDS, root_page_no,
|
||||
MLOG_4BYTES, mtr);
|
||||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
DICT_HDR_SPACE, 0, DICT_COLUMNS_ID,
|
||||
srv_sys->dummy_ind1, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
mlog_write_ulint(dict_header + DICT_HDR_COLUMNS, root_page_no,
|
||||
MLOG_4BYTES, mtr);
|
||||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
DICT_HDR_SPACE, 0, DICT_INDEXES_ID,
|
||||
srv_sys->dummy_ind1, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
mlog_write_ulint(dict_header + DICT_HDR_INDEXES, root_page_no,
|
||||
MLOG_4BYTES, mtr);
|
||||
/*--------------------------*/
|
||||
root_page_no = btr_create(DICT_CLUSTERED | DICT_UNIQUE,
|
||||
DICT_HDR_SPACE, 0, DICT_FIELDS_ID,
|
||||
srv_sys->dummy_ind1, mtr);
|
||||
if (root_page_no == FIL_NULL) {
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
mlog_write_ulint(dict_header + DICT_HDR_FIELDS, root_page_no,
|
||||
MLOG_4BYTES, mtr);
|
||||
/*--------------------------*/
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Initializes the data dictionary memory structures when the database is
|
||||
started. This function is also called when the data dictionary is created. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_boot(void)
|
||||
/*===========*/
|
||||
{
|
||||
dict_table_t* table;
|
||||
dict_index_t* index;
|
||||
dict_hdr_t* dict_hdr;
|
||||
mem_heap_t* heap;
|
||||
mtr_t mtr;
|
||||
ulint error;
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
/* Create the hash tables etc. */
|
||||
dict_init();
|
||||
|
||||
heap = mem_heap_create(450);
|
||||
|
||||
mutex_enter(&(dict_sys->mutex));
|
||||
|
||||
/* Get the dictionary header */
|
||||
dict_hdr = dict_hdr_get(&mtr);
|
||||
|
||||
/* Because we only write new row ids to disk-based data structure
|
||||
(dictionary header) when it is divisible by
|
||||
DICT_HDR_ROW_ID_WRITE_MARGIN, in recovery we will not recover
|
||||
the latest value of the row id counter. Therefore we advance
|
||||
the counter at the database startup to avoid overlapping values.
|
||||
Note that when a user after database startup first time asks for
|
||||
a new row id, then because the counter is now divisible by
|
||||
..._MARGIN, it will immediately be updated to the disk-based
|
||||
header. */
|
||||
|
||||
dict_sys->row_id = ut_dulint_add(
|
||||
ut_dulint_align_up(mtr_read_dulint(dict_hdr + DICT_HDR_ROW_ID,
|
||||
&mtr),
|
||||
DICT_HDR_ROW_ID_WRITE_MARGIN),
|
||||
DICT_HDR_ROW_ID_WRITE_MARGIN);
|
||||
|
||||
/* Insert into the dictionary cache the descriptions of the basic
|
||||
system tables */
|
||||
/*-------------------------*/
|
||||
table = dict_mem_table_create("SYS_TABLES", DICT_HDR_SPACE, 8, 0);
|
||||
table->n_mysql_handles_opened = 1; /* for pin */
|
||||
|
||||
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
|
||||
/* ROW_FORMAT = (N_COLS >> 31) ? COMPACT : REDUNDANT */
|
||||
dict_mem_table_add_col(table, heap, "N_COLS", DATA_INT, 0, 4);
|
||||
/* TYPE is either DICT_TABLE_ORDINARY, or (TYPE & DICT_TF_COMPACT)
|
||||
and (TYPE & DICT_TF_FORMAT_MASK) are nonzero and TYPE = table->flags */
|
||||
dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
|
||||
|
||||
table->id = DICT_TABLES_ID;
|
||||
|
||||
dict_table_add_to_cache(table, heap);
|
||||
dict_sys->sys_tables = table;
|
||||
mem_heap_empty(heap);
|
||||
|
||||
index = dict_mem_index_create("SYS_TABLES", "CLUST_IND",
|
||||
DICT_HDR_SPACE,
|
||||
DICT_UNIQUE | DICT_CLUSTERED, 1);
|
||||
|
||||
dict_mem_index_add_field(index, "NAME", 0);
|
||||
|
||||
index->id = DICT_TABLES_ID;
|
||||
|
||||
error = dict_index_add_to_cache(table, index,
|
||||
mtr_read_ulint(dict_hdr
|
||||
+ DICT_HDR_TABLES,
|
||||
MLOG_4BYTES, &mtr),
|
||||
FALSE);
|
||||
ut_a(error == DB_SUCCESS);
|
||||
|
||||
/*-------------------------*/
|
||||
index = dict_mem_index_create("SYS_TABLES", "ID_IND",
|
||||
DICT_HDR_SPACE, DICT_UNIQUE, 1);
|
||||
dict_mem_index_add_field(index, "ID", 0);
|
||||
|
||||
index->id = DICT_TABLE_IDS_ID;
|
||||
error = dict_index_add_to_cache(table, index,
|
||||
mtr_read_ulint(dict_hdr
|
||||
+ DICT_HDR_TABLE_IDS,
|
||||
MLOG_4BYTES, &mtr),
|
||||
FALSE);
|
||||
ut_a(error == DB_SUCCESS);
|
||||
|
||||
/*-------------------------*/
|
||||
table = dict_mem_table_create("SYS_COLUMNS", DICT_HDR_SPACE, 7, 0);
|
||||
table->n_mysql_handles_opened = 1; /* for pin */
|
||||
|
||||
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "POS", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "MTYPE", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "PRTYPE", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "LEN", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "PREC", DATA_INT, 0, 4);
|
||||
|
||||
table->id = DICT_COLUMNS_ID;
|
||||
|
||||
dict_table_add_to_cache(table, heap);
|
||||
dict_sys->sys_columns = table;
|
||||
mem_heap_empty(heap);
|
||||
|
||||
index = dict_mem_index_create("SYS_COLUMNS", "CLUST_IND",
|
||||
DICT_HDR_SPACE,
|
||||
DICT_UNIQUE | DICT_CLUSTERED, 2);
|
||||
|
||||
dict_mem_index_add_field(index, "TABLE_ID", 0);
|
||||
dict_mem_index_add_field(index, "POS", 0);
|
||||
|
||||
index->id = DICT_COLUMNS_ID;
|
||||
error = dict_index_add_to_cache(table, index,
|
||||
mtr_read_ulint(dict_hdr
|
||||
+ DICT_HDR_COLUMNS,
|
||||
MLOG_4BYTES, &mtr),
|
||||
FALSE);
|
||||
ut_a(error == DB_SUCCESS);
|
||||
|
||||
/*-------------------------*/
|
||||
table = dict_mem_table_create("SYS_INDEXES", DICT_HDR_SPACE, 7, 0);
|
||||
table->n_mysql_handles_opened = 1; /* for pin */
|
||||
|
||||
dict_mem_table_add_col(table, heap, "TABLE_ID", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "ID", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "NAME", DATA_BINARY, 0, 0);
|
||||
dict_mem_table_add_col(table, heap, "N_FIELDS", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "PAGE_NO", DATA_INT, 0, 4);
|
||||
|
||||
/* The '+ 2' below comes from the 2 system fields */
|
||||
#if DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2
|
||||
#error "DICT_SYS_INDEXES_PAGE_NO_FIELD != 6 + 2"
|
||||
#endif
|
||||
#if DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2
|
||||
#error "DICT_SYS_INDEXES_SPACE_NO_FIELD != 5 + 2"
|
||||
#endif
|
||||
#if DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2
|
||||
#error "DICT_SYS_INDEXES_TYPE_FIELD != 4 + 2"
|
||||
#endif
|
||||
|
||||
table->id = DICT_INDEXES_ID;
|
||||
dict_table_add_to_cache(table, heap);
|
||||
dict_sys->sys_indexes = table;
|
||||
mem_heap_empty(heap);
|
||||
|
||||
index = dict_mem_index_create("SYS_INDEXES", "CLUST_IND",
|
||||
DICT_HDR_SPACE,
|
||||
DICT_UNIQUE | DICT_CLUSTERED, 2);
|
||||
|
||||
dict_mem_index_add_field(index, "TABLE_ID", 0);
|
||||
dict_mem_index_add_field(index, "ID", 0);
|
||||
|
||||
index->id = DICT_INDEXES_ID;
|
||||
error = dict_index_add_to_cache(table, index,
|
||||
mtr_read_ulint(dict_hdr
|
||||
+ DICT_HDR_INDEXES,
|
||||
MLOG_4BYTES, &mtr),
|
||||
FALSE);
|
||||
ut_a(error == DB_SUCCESS);
|
||||
|
||||
/*-------------------------*/
|
||||
table = dict_mem_table_create("SYS_FIELDS", DICT_HDR_SPACE, 3, 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, "POS", DATA_INT, 0, 4);
|
||||
dict_mem_table_add_col(table, heap, "COL_NAME", DATA_BINARY, 0, 0);
|
||||
|
||||
table->id = DICT_FIELDS_ID;
|
||||
dict_table_add_to_cache(table, heap);
|
||||
dict_sys->sys_fields = table;
|
||||
mem_heap_free(heap);
|
||||
|
||||
index = dict_mem_index_create("SYS_FIELDS", "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, "POS", 0);
|
||||
|
||||
index->id = DICT_FIELDS_ID;
|
||||
error = dict_index_add_to_cache(table, index,
|
||||
mtr_read_ulint(dict_hdr
|
||||
+ DICT_HDR_FIELDS,
|
||||
MLOG_4BYTES, &mtr),
|
||||
FALSE);
|
||||
ut_a(error == DB_SUCCESS);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
/*-------------------------*/
|
||||
|
||||
/* Initialize the insert buffer table and index for each tablespace */
|
||||
|
||||
ibuf_init_at_db_start();
|
||||
|
||||
/* Load definitions of other indexes on system tables */
|
||||
|
||||
dict_load_sys_table(dict_sys->sys_tables);
|
||||
dict_load_sys_table(dict_sys->sys_columns);
|
||||
dict_load_sys_table(dict_sys->sys_indexes);
|
||||
dict_load_sys_table(dict_sys->sys_fields);
|
||||
|
||||
mutex_exit(&(dict_sys->mutex));
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Inserts the basic system table data into themselves in the database
|
||||
creation. */
|
||||
static
|
||||
void
|
||||
dict_insert_initial_data(void)
|
||||
/*==========================*/
|
||||
{
|
||||
/* Does nothing yet */
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Creates and initializes the data dictionary at the database creation. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_create(void)
|
||||
/*=============*/
|
||||
{
|
||||
mtr_t mtr;
|
||||
|
||||
mtr_start(&mtr);
|
||||
|
||||
dict_hdr_create(&mtr);
|
||||
|
||||
mtr_commit(&mtr);
|
||||
|
||||
dict_boot();
|
||||
|
||||
dict_insert_initial_data();
|
||||
}
|
||||
1511
storage/xtradb/dict/dict0crea.c
Normal file
1511
storage/xtradb/dict/dict0crea.c
Normal file
File diff suppressed because it is too large
Load diff
4810
storage/xtradb/dict/dict0dict.c
Normal file
4810
storage/xtradb/dict/dict0dict.c
Normal file
File diff suppressed because it is too large
Load diff
1460
storage/xtradb/dict/dict0load.c
Normal file
1460
storage/xtradb/dict/dict0load.c
Normal file
File diff suppressed because it is too large
Load diff
308
storage/xtradb/dict/dict0mem.c
Normal file
308
storage/xtradb/dict/dict0mem.c
Normal file
|
|
@ -0,0 +1,308 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
Data dictionary memory object creation
|
||||
|
||||
Created 1/8/1996 Heikki Tuuri
|
||||
***********************************************************************/
|
||||
|
||||
#include "dict0mem.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "dict0mem.ic"
|
||||
#endif
|
||||
|
||||
#include "rem0rec.h"
|
||||
#include "data0type.h"
|
||||
#include "mach0data.h"
|
||||
#include "dict0dict.h"
|
||||
#include "lock0lock.h"
|
||||
|
||||
#define DICT_HEAP_SIZE 100 /* initial memory heap size when
|
||||
creating a table or index object */
|
||||
|
||||
/**************************************************************************
|
||||
Creates a table memory object. */
|
||||
UNIV_INTERN
|
||||
dict_table_t*
|
||||
dict_mem_table_create(
|
||||
/*==================*/
|
||||
/* out, own: table object */
|
||||
const char* name, /* in: table name */
|
||||
ulint space, /* in: space where the clustered index of
|
||||
the table is placed; this parameter is
|
||||
ignored if the table is made a member of
|
||||
a cluster */
|
||||
ulint n_cols, /* in: number of columns */
|
||||
ulint flags) /* in: table flags */
|
||||
{
|
||||
dict_table_t* table;
|
||||
mem_heap_t* heap;
|
||||
|
||||
ut_ad(name);
|
||||
ut_a(!(flags & (~0 << DICT_TF_BITS)));
|
||||
|
||||
heap = mem_heap_create(DICT_HEAP_SIZE);
|
||||
|
||||
table = mem_heap_zalloc(heap, sizeof(dict_table_t));
|
||||
|
||||
table->heap = heap;
|
||||
|
||||
table->flags = (unsigned int) flags;
|
||||
table->name = mem_heap_strdup(heap, name);
|
||||
table->space = (unsigned int) space;
|
||||
table->n_cols = (unsigned int) (n_cols + DATA_N_SYS_COLS);
|
||||
|
||||
table->cols = mem_heap_alloc(heap, (n_cols + DATA_N_SYS_COLS)
|
||||
* sizeof(dict_col_t));
|
||||
|
||||
table->autoinc_lock = mem_heap_alloc(heap, lock_get_size());
|
||||
|
||||
mutex_create(&table->autoinc_mutex, SYNC_DICT_AUTOINC_MUTEX);
|
||||
|
||||
table->autoinc = 0;
|
||||
|
||||
/* The number of transactions that are either waiting on the
|
||||
AUTOINC lock or have been granted the lock. */
|
||||
table->n_waiting_or_granted_auto_inc_locks = 0;
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
table->magic_n = DICT_TABLE_MAGIC_N;
|
||||
#endif /* UNIV_DEBUG */
|
||||
return(table);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Free a table memory object. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_mem_table_free(
|
||||
/*================*/
|
||||
dict_table_t* table) /* in: table */
|
||||
{
|
||||
ut_ad(table);
|
||||
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
||||
ut_d(table->cached = FALSE);
|
||||
|
||||
mutex_free(&(table->autoinc_mutex));
|
||||
mem_heap_free(table->heap);
|
||||
}
|
||||
|
||||
/********************************************************************
|
||||
Append 'name' to 'col_names' (@see dict_table_t::col_names). */
|
||||
static
|
||||
const char*
|
||||
dict_add_col_name(
|
||||
/*==============*/
|
||||
/* out: new column names array */
|
||||
const char* col_names, /* in: existing column names, or
|
||||
NULL */
|
||||
ulint cols, /* in: number of existing columns */
|
||||
const char* name, /* in: new column name */
|
||||
mem_heap_t* heap) /* in: heap */
|
||||
{
|
||||
ulint old_len;
|
||||
ulint new_len;
|
||||
ulint total_len;
|
||||
char* res;
|
||||
|
||||
ut_ad(!cols == !col_names);
|
||||
|
||||
/* Find out length of existing array. */
|
||||
if (col_names) {
|
||||
const char* s = col_names;
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < cols; i++) {
|
||||
s += strlen(s) + 1;
|
||||
}
|
||||
|
||||
old_len = s - col_names;
|
||||
} else {
|
||||
old_len = 0;
|
||||
}
|
||||
|
||||
new_len = strlen(name) + 1;
|
||||
total_len = old_len + new_len;
|
||||
|
||||
res = mem_heap_alloc(heap, total_len);
|
||||
|
||||
if (old_len > 0) {
|
||||
memcpy(res, col_names, old_len);
|
||||
}
|
||||
|
||||
memcpy(res + old_len, name, new_len);
|
||||
|
||||
return(res);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Adds a column definition to a table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_mem_table_add_col(
|
||||
/*===================*/
|
||||
dict_table_t* table, /* in: table */
|
||||
mem_heap_t* heap, /* in: temporary memory heap, or NULL */
|
||||
const char* name, /* in: column name, or NULL */
|
||||
ulint mtype, /* in: main datatype */
|
||||
ulint prtype, /* in: precise type */
|
||||
ulint len) /* in: precision */
|
||||
{
|
||||
dict_col_t* col;
|
||||
ulint mbminlen;
|
||||
ulint mbmaxlen;
|
||||
ulint i;
|
||||
|
||||
ut_ad(table);
|
||||
ut_ad(table->magic_n == DICT_TABLE_MAGIC_N);
|
||||
ut_ad(!heap == !name);
|
||||
|
||||
i = table->n_def++;
|
||||
|
||||
if (name) {
|
||||
if (UNIV_UNLIKELY(table->n_def == table->n_cols)) {
|
||||
heap = table->heap;
|
||||
}
|
||||
if (UNIV_LIKELY(i) && UNIV_UNLIKELY(!table->col_names)) {
|
||||
/* All preceding column names are empty. */
|
||||
char* s = mem_heap_zalloc(heap, table->n_def);
|
||||
table->col_names = s;
|
||||
}
|
||||
|
||||
table->col_names = dict_add_col_name(table->col_names,
|
||||
i, name, heap);
|
||||
}
|
||||
|
||||
col = dict_table_get_nth_col(table, i);
|
||||
|
||||
col->ind = (unsigned int) i;
|
||||
col->ord_part = 0;
|
||||
|
||||
col->mtype = (unsigned int) mtype;
|
||||
col->prtype = (unsigned int) prtype;
|
||||
col->len = (unsigned int) len;
|
||||
|
||||
dtype_get_mblen(mtype, prtype, &mbminlen, &mbmaxlen);
|
||||
|
||||
col->mbminlen = (unsigned int) mbminlen;
|
||||
col->mbmaxlen = (unsigned int) mbmaxlen;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Creates an index memory object. */
|
||||
UNIV_INTERN
|
||||
dict_index_t*
|
||||
dict_mem_index_create(
|
||||
/*==================*/
|
||||
/* out, own: index object */
|
||||
const char* table_name, /* in: table name */
|
||||
const char* index_name, /* in: index name */
|
||||
ulint space, /* in: space where the index tree is
|
||||
placed, ignored if the index is of
|
||||
the clustered type */
|
||||
ulint type, /* in: DICT_UNIQUE,
|
||||
DICT_CLUSTERED, ... ORed */
|
||||
ulint n_fields) /* in: number of fields */
|
||||
{
|
||||
dict_index_t* index;
|
||||
mem_heap_t* heap;
|
||||
|
||||
ut_ad(table_name && index_name);
|
||||
|
||||
heap = mem_heap_create(DICT_HEAP_SIZE);
|
||||
index = mem_heap_zalloc(heap, sizeof(dict_index_t));
|
||||
|
||||
index->heap = heap;
|
||||
|
||||
index->type = type;
|
||||
index->space = (unsigned int) space;
|
||||
index->name = mem_heap_strdup(heap, index_name);
|
||||
index->table_name = table_name;
|
||||
index->n_fields = (unsigned int) n_fields;
|
||||
index->fields = mem_heap_alloc(heap, 1 + n_fields
|
||||
* sizeof(dict_field_t));
|
||||
/* The '1 +' above prevents allocation
|
||||
of an empty mem block */
|
||||
#ifdef UNIV_DEBUG
|
||||
index->magic_n = DICT_INDEX_MAGIC_N;
|
||||
#endif /* UNIV_DEBUG */
|
||||
return(index);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Creates and initializes a foreign constraint memory object. */
|
||||
UNIV_INTERN
|
||||
dict_foreign_t*
|
||||
dict_mem_foreign_create(void)
|
||||
/*=========================*/
|
||||
/* out, own: foreign constraint struct */
|
||||
{
|
||||
dict_foreign_t* foreign;
|
||||
mem_heap_t* heap;
|
||||
|
||||
heap = mem_heap_create(100);
|
||||
|
||||
foreign = mem_heap_zalloc(heap, sizeof(dict_foreign_t));
|
||||
|
||||
foreign->heap = heap;
|
||||
|
||||
return(foreign);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Adds a field definition to an index. NOTE: does not take a copy
|
||||
of the column name if the field is a column. The memory occupied
|
||||
by the column name may be released only after publishing the index. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_mem_index_add_field(
|
||||
/*=====================*/
|
||||
dict_index_t* index, /* in: index */
|
||||
const char* name, /* in: column name */
|
||||
ulint prefix_len) /* in: 0 or the column prefix length
|
||||
in a MySQL index like
|
||||
INDEX (textcol(25)) */
|
||||
{
|
||||
dict_field_t* field;
|
||||
|
||||
ut_ad(index);
|
||||
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
||||
|
||||
index->n_def++;
|
||||
|
||||
field = dict_index_get_nth_field(index, index->n_def - 1);
|
||||
|
||||
field->name = name;
|
||||
field->prefix_len = (unsigned int) prefix_len;
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Frees an index memory object. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
dict_mem_index_free(
|
||||
/*================*/
|
||||
dict_index_t* index) /* in: index */
|
||||
{
|
||||
ut_ad(index);
|
||||
ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
|
||||
|
||||
mem_heap_free(index->heap);
|
||||
}
|
||||
64
storage/xtradb/dyn/dyn0dyn.c
Normal file
64
storage/xtradb/dyn/dyn0dyn.c
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1996, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
The dynamically allocated array
|
||||
|
||||
Created 2/5/1996 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "dyn0dyn.h"
|
||||
#ifdef UNIV_NONINL
|
||||
#include "dyn0dyn.ic"
|
||||
#endif
|
||||
|
||||
/****************************************************************
|
||||
Adds a new block to a dyn array. */
|
||||
UNIV_INTERN
|
||||
dyn_block_t*
|
||||
dyn_array_add_block(
|
||||
/*================*/
|
||||
/* out: created block */
|
||||
dyn_array_t* arr) /* in: dyn array */
|
||||
{
|
||||
mem_heap_t* heap;
|
||||
dyn_block_t* block;
|
||||
|
||||
ut_ad(arr);
|
||||
ut_ad(arr->magic_n == DYN_BLOCK_MAGIC_N);
|
||||
|
||||
if (arr->heap == NULL) {
|
||||
UT_LIST_INIT(arr->base);
|
||||
UT_LIST_ADD_FIRST(list, arr->base, arr);
|
||||
|
||||
arr->heap = mem_heap_create(sizeof(dyn_block_t));
|
||||
}
|
||||
|
||||
block = dyn_array_get_last_block(arr);
|
||||
block->used = block->used | DYN_BLOCK_FULL_FLAG;
|
||||
|
||||
heap = arr->heap;
|
||||
|
||||
block = mem_heap_alloc(heap, sizeof(dyn_block_t));
|
||||
|
||||
block->used = 0;
|
||||
|
||||
UT_LIST_ADD_LAST(list, arr->base, block);
|
||||
|
||||
return(block);
|
||||
}
|
||||
851
storage/xtradb/eval/eval0eval.c
Normal file
851
storage/xtradb/eval/eval0eval.c
Normal file
|
|
@ -0,0 +1,851 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
SQL evaluator: evaluates simple data structures, like expressions, in
|
||||
a query graph
|
||||
|
||||
Created 12/29/1997 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "eval0eval.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "eval0eval.ic"
|
||||
#endif
|
||||
|
||||
#include "data0data.h"
|
||||
#include "row0sel.h"
|
||||
|
||||
/* The RND function seed */
|
||||
static ulint eval_rnd = 128367121;
|
||||
|
||||
/* Dummy adress used when we should allocate a buffer of size 0 in
|
||||
the function below */
|
||||
|
||||
static byte eval_dummy;
|
||||
|
||||
/*********************************************************************
|
||||
Allocate a buffer from global dynamic memory for a value of a que_node.
|
||||
NOTE that this memory must be explicitly freed when the query graph is
|
||||
freed. If the node already has an allocated buffer, that buffer is freed
|
||||
here. NOTE that this is the only function where dynamic memory should be
|
||||
allocated for a query node val field. */
|
||||
UNIV_INTERN
|
||||
byte*
|
||||
eval_node_alloc_val_buf(
|
||||
/*====================*/
|
||||
/* out: pointer to allocated buffer */
|
||||
que_node_t* node, /* in: query graph node; sets the val field
|
||||
data field to point to the new buffer, and
|
||||
len field equal to size */
|
||||
ulint size) /* in: buffer size */
|
||||
{
|
||||
dfield_t* dfield;
|
||||
byte* data;
|
||||
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
|
||||
|| que_node_get_type(node) == QUE_NODE_FUNC);
|
||||
|
||||
dfield = que_node_get_val(node);
|
||||
|
||||
data = dfield_get_data(dfield);
|
||||
|
||||
if (data && data != &eval_dummy) {
|
||||
mem_free(data);
|
||||
}
|
||||
|
||||
if (size == 0) {
|
||||
data = &eval_dummy;
|
||||
} else {
|
||||
data = mem_alloc(size);
|
||||
}
|
||||
|
||||
que_node_set_val_buf_size(node, size);
|
||||
|
||||
dfield_set_data(dfield, data, size);
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Free the buffer from global dynamic memory for a value of a que_node,
|
||||
if it has been allocated in the above function. The freeing for pushed
|
||||
column values is done in sel_col_prefetch_buf_free. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
eval_node_free_val_buf(
|
||||
/*===================*/
|
||||
que_node_t* node) /* in: query graph node */
|
||||
{
|
||||
dfield_t* dfield;
|
||||
byte* data;
|
||||
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_SYMBOL
|
||||
|| que_node_get_type(node) == QUE_NODE_FUNC);
|
||||
|
||||
dfield = que_node_get_val(node);
|
||||
|
||||
data = dfield_get_data(dfield);
|
||||
|
||||
if (que_node_get_val_buf_size(node) > 0) {
|
||||
ut_a(data);
|
||||
|
||||
mem_free(data);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a comparison node. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
eval_cmp(
|
||||
/*=====*/
|
||||
/* out: the result of the comparison */
|
||||
func_node_t* cmp_node) /* in: comparison node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
int res;
|
||||
ibool val;
|
||||
int func;
|
||||
|
||||
ut_ad(que_node_get_type(cmp_node) == QUE_NODE_FUNC);
|
||||
|
||||
arg1 = cmp_node->args;
|
||||
arg2 = que_node_get_next(arg1);
|
||||
|
||||
res = cmp_dfield_dfield(que_node_get_val(arg1),
|
||||
que_node_get_val(arg2));
|
||||
val = TRUE;
|
||||
|
||||
func = cmp_node->func;
|
||||
|
||||
if (func == '=') {
|
||||
if (res != 0) {
|
||||
val = FALSE;
|
||||
}
|
||||
} else if (func == '<') {
|
||||
if (res != -1) {
|
||||
val = FALSE;
|
||||
}
|
||||
} else if (func == PARS_LE_TOKEN) {
|
||||
if (res == 1) {
|
||||
val = FALSE;
|
||||
}
|
||||
} else if (func == PARS_NE_TOKEN) {
|
||||
if (res == 0) {
|
||||
val = FALSE;
|
||||
}
|
||||
} else if (func == PARS_GE_TOKEN) {
|
||||
if (res == -1) {
|
||||
val = FALSE;
|
||||
}
|
||||
} else {
|
||||
ut_ad(func == '>');
|
||||
|
||||
if (res != 1) {
|
||||
val = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
eval_node_set_ibool_val(cmp_node, val);
|
||||
|
||||
return(val);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a logical operation node. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_logical(
|
||||
/*=========*/
|
||||
func_node_t* logical_node) /* in: logical operation node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
ibool val1;
|
||||
ibool val2 = 0; /* remove warning */
|
||||
ibool val = 0; /* remove warning */
|
||||
int func;
|
||||
|
||||
ut_ad(que_node_get_type(logical_node) == QUE_NODE_FUNC);
|
||||
|
||||
arg1 = logical_node->args;
|
||||
arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is 'NOT' */
|
||||
|
||||
val1 = eval_node_get_ibool_val(arg1);
|
||||
|
||||
if (arg2) {
|
||||
val2 = eval_node_get_ibool_val(arg2);
|
||||
}
|
||||
|
||||
func = logical_node->func;
|
||||
|
||||
if (func == PARS_AND_TOKEN) {
|
||||
val = val1 & val2;
|
||||
} else if (func == PARS_OR_TOKEN) {
|
||||
val = val1 | val2;
|
||||
} else if (func == PARS_NOT_TOKEN) {
|
||||
val = TRUE - val1;
|
||||
} else {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
eval_node_set_ibool_val(logical_node, val);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates an arithmetic operation node. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_arith(
|
||||
/*=======*/
|
||||
func_node_t* arith_node) /* in: arithmetic operation node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
lint val1;
|
||||
lint val2 = 0; /* remove warning */
|
||||
lint val;
|
||||
int func;
|
||||
|
||||
ut_ad(que_node_get_type(arith_node) == QUE_NODE_FUNC);
|
||||
|
||||
arg1 = arith_node->args;
|
||||
arg2 = que_node_get_next(arg1); /* arg2 is NULL if func is unary '-' */
|
||||
|
||||
val1 = eval_node_get_int_val(arg1);
|
||||
|
||||
if (arg2) {
|
||||
val2 = eval_node_get_int_val(arg2);
|
||||
}
|
||||
|
||||
func = arith_node->func;
|
||||
|
||||
if (func == '+') {
|
||||
val = val1 + val2;
|
||||
} else if ((func == '-') && arg2) {
|
||||
val = val1 - val2;
|
||||
} else if (func == '-') {
|
||||
val = -val1;
|
||||
} else if (func == '*') {
|
||||
val = val1 * val2;
|
||||
} else {
|
||||
ut_ad(func == '/');
|
||||
val = val1 / val2;
|
||||
}
|
||||
|
||||
eval_node_set_int_val(arith_node, val);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates an aggregate operation node. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_aggregate(
|
||||
/*===========*/
|
||||
func_node_t* node) /* in: aggregate operation node */
|
||||
{
|
||||
que_node_t* arg;
|
||||
lint val;
|
||||
lint arg_val;
|
||||
int func;
|
||||
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_FUNC);
|
||||
|
||||
val = eval_node_get_int_val(node);
|
||||
|
||||
func = node->func;
|
||||
|
||||
if (func == PARS_COUNT_TOKEN) {
|
||||
|
||||
val = val + 1;
|
||||
} else {
|
||||
ut_ad(func == PARS_SUM_TOKEN);
|
||||
|
||||
arg = node->args;
|
||||
arg_val = eval_node_get_int_val(arg);
|
||||
|
||||
val = val + arg_val;
|
||||
}
|
||||
|
||||
eval_node_set_int_val(node, val);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a predefined function node where the function is not relevant
|
||||
in benchmarks. */
|
||||
static
|
||||
void
|
||||
eval_predefined_2(
|
||||
/*==============*/
|
||||
func_node_t* func_node) /* in: predefined function node */
|
||||
{
|
||||
que_node_t* arg;
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2 = 0; /* remove warning (??? bug ???) */
|
||||
lint int_val;
|
||||
byte* data;
|
||||
ulint len1;
|
||||
ulint len2;
|
||||
int func;
|
||||
ulint i;
|
||||
|
||||
ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
|
||||
|
||||
arg1 = func_node->args;
|
||||
|
||||
if (arg1) {
|
||||
arg2 = que_node_get_next(arg1);
|
||||
}
|
||||
|
||||
func = func_node->func;
|
||||
|
||||
if (func == PARS_PRINTF_TOKEN) {
|
||||
|
||||
arg = arg1;
|
||||
|
||||
while (arg) {
|
||||
dfield_print(que_node_get_val(arg));
|
||||
|
||||
arg = que_node_get_next(arg);
|
||||
}
|
||||
|
||||
putc('\n', stderr);
|
||||
|
||||
} else if (func == PARS_ASSERT_TOKEN) {
|
||||
|
||||
if (!eval_node_get_ibool_val(arg1)) {
|
||||
fputs("SQL assertion fails in a stored procedure!\n",
|
||||
stderr);
|
||||
}
|
||||
|
||||
ut_a(eval_node_get_ibool_val(arg1));
|
||||
|
||||
/* This function, or more precisely, a debug procedure,
|
||||
returns no value */
|
||||
|
||||
} else if (func == PARS_RND_TOKEN) {
|
||||
|
||||
len1 = (ulint)eval_node_get_int_val(arg1);
|
||||
len2 = (ulint)eval_node_get_int_val(arg2);
|
||||
|
||||
ut_ad(len2 >= len1);
|
||||
|
||||
if (len2 > len1) {
|
||||
int_val = (lint) (len1
|
||||
+ (eval_rnd % (len2 - len1 + 1)));
|
||||
} else {
|
||||
int_val = (lint) len1;
|
||||
}
|
||||
|
||||
eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
|
||||
|
||||
eval_node_set_int_val(func_node, int_val);
|
||||
|
||||
} else if (func == PARS_RND_STR_TOKEN) {
|
||||
|
||||
len1 = (ulint)eval_node_get_int_val(arg1);
|
||||
|
||||
data = eval_node_ensure_val_buf(func_node, len1);
|
||||
|
||||
for (i = 0; i < len1; i++) {
|
||||
data[i] = (byte)(97 + (eval_rnd % 3));
|
||||
|
||||
eval_rnd = ut_rnd_gen_next_ulint(eval_rnd);
|
||||
}
|
||||
} else {
|
||||
ut_error;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a notfound-function node. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_notfound(
|
||||
/*==========*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
sym_node_t* cursor;
|
||||
sel_node_t* sel_node;
|
||||
ibool ibool_val;
|
||||
|
||||
arg1 = func_node->args;
|
||||
arg2 = que_node_get_next(arg1);
|
||||
|
||||
ut_ad(func_node->func == PARS_NOTFOUND_TOKEN);
|
||||
|
||||
cursor = arg1;
|
||||
|
||||
ut_ad(que_node_get_type(cursor) == QUE_NODE_SYMBOL);
|
||||
|
||||
if (cursor->token_type == SYM_LIT) {
|
||||
|
||||
ut_ad(ut_memcmp(dfield_get_data(que_node_get_val(cursor)),
|
||||
"SQL", 3) == 0);
|
||||
|
||||
sel_node = cursor->sym_table->query_graph->last_sel_node;
|
||||
} else {
|
||||
sel_node = cursor->alias->cursor_def;
|
||||
}
|
||||
|
||||
if (sel_node->state == SEL_NODE_NO_MORE_ROWS) {
|
||||
ibool_val = TRUE;
|
||||
} else {
|
||||
ibool_val = FALSE;
|
||||
}
|
||||
|
||||
eval_node_set_ibool_val(func_node, ibool_val);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a substr-function node. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_substr(
|
||||
/*========*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
que_node_t* arg3;
|
||||
dfield_t* dfield;
|
||||
byte* str1;
|
||||
ulint len1;
|
||||
ulint len2;
|
||||
|
||||
arg1 = func_node->args;
|
||||
arg2 = que_node_get_next(arg1);
|
||||
|
||||
ut_ad(func_node->func == PARS_SUBSTR_TOKEN);
|
||||
|
||||
arg3 = que_node_get_next(arg2);
|
||||
|
||||
str1 = dfield_get_data(que_node_get_val(arg1));
|
||||
|
||||
len1 = (ulint)eval_node_get_int_val(arg2);
|
||||
len2 = (ulint)eval_node_get_int_val(arg3);
|
||||
|
||||
dfield = que_node_get_val(func_node);
|
||||
|
||||
dfield_set_data(dfield, str1 + len1, len2);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a replstr-procedure node. */
|
||||
static
|
||||
void
|
||||
eval_replstr(
|
||||
/*=========*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
que_node_t* arg3;
|
||||
que_node_t* arg4;
|
||||
byte* str1;
|
||||
byte* str2;
|
||||
ulint len1;
|
||||
ulint len2;
|
||||
|
||||
arg1 = func_node->args;
|
||||
arg2 = que_node_get_next(arg1);
|
||||
|
||||
ut_ad(que_node_get_type(arg1) == QUE_NODE_SYMBOL);
|
||||
|
||||
arg3 = que_node_get_next(arg2);
|
||||
arg4 = que_node_get_next(arg3);
|
||||
|
||||
str1 = dfield_get_data(que_node_get_val(arg1));
|
||||
str2 = dfield_get_data(que_node_get_val(arg2));
|
||||
|
||||
len1 = (ulint)eval_node_get_int_val(arg3);
|
||||
len2 = (ulint)eval_node_get_int_val(arg4);
|
||||
|
||||
if ((dfield_get_len(que_node_get_val(arg1)) < len1 + len2)
|
||||
|| (dfield_get_len(que_node_get_val(arg2)) < len2)) {
|
||||
|
||||
ut_error;
|
||||
}
|
||||
|
||||
ut_memcpy(str1 + len1, str2, len2);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates an instr-function node. */
|
||||
static
|
||||
void
|
||||
eval_instr(
|
||||
/*=======*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
dfield_t* dfield1;
|
||||
dfield_t* dfield2;
|
||||
lint int_val;
|
||||
byte* str1;
|
||||
byte* str2;
|
||||
byte match_char;
|
||||
ulint len1;
|
||||
ulint len2;
|
||||
ulint i;
|
||||
ulint j;
|
||||
|
||||
arg1 = func_node->args;
|
||||
arg2 = que_node_get_next(arg1);
|
||||
|
||||
dfield1 = que_node_get_val(arg1);
|
||||
dfield2 = que_node_get_val(arg2);
|
||||
|
||||
str1 = dfield_get_data(dfield1);
|
||||
str2 = dfield_get_data(dfield2);
|
||||
|
||||
len1 = dfield_get_len(dfield1);
|
||||
len2 = dfield_get_len(dfield2);
|
||||
|
||||
if (len2 == 0) {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
match_char = str2[0];
|
||||
|
||||
for (i = 0; i < len1; i++) {
|
||||
/* In this outer loop, the number of matched characters is 0 */
|
||||
|
||||
if (str1[i] == match_char) {
|
||||
|
||||
if (i + len2 > len1) {
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
for (j = 1;; j++) {
|
||||
/* We have already matched j characters */
|
||||
|
||||
if (j == len2) {
|
||||
int_val = i + 1;
|
||||
|
||||
goto match_found;
|
||||
}
|
||||
|
||||
if (str1[i + j] != str2[j]) {
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int_val = 0;
|
||||
|
||||
match_found:
|
||||
eval_node_set_int_val(func_node, int_val);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a predefined function node. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_binary_to_number(
|
||||
/*==================*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
dfield_t* dfield;
|
||||
byte* str1;
|
||||
byte* str2;
|
||||
ulint len1;
|
||||
ulint int_val;
|
||||
|
||||
arg1 = func_node->args;
|
||||
|
||||
dfield = que_node_get_val(arg1);
|
||||
|
||||
str1 = dfield_get_data(dfield);
|
||||
len1 = dfield_get_len(dfield);
|
||||
|
||||
if (len1 > 4) {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
if (len1 == 4) {
|
||||
str2 = str1;
|
||||
} else {
|
||||
int_val = 0;
|
||||
str2 = (byte*)&int_val;
|
||||
|
||||
ut_memcpy(str2 + (4 - len1), str1, len1);
|
||||
}
|
||||
|
||||
eval_node_copy_and_alloc_val(func_node, str2, 4);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a predefined function node. */
|
||||
static
|
||||
void
|
||||
eval_concat(
|
||||
/*========*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg;
|
||||
dfield_t* dfield;
|
||||
byte* data;
|
||||
ulint len;
|
||||
ulint len1;
|
||||
|
||||
arg = func_node->args;
|
||||
len = 0;
|
||||
|
||||
while (arg) {
|
||||
len1 = dfield_get_len(que_node_get_val(arg));
|
||||
|
||||
len += len1;
|
||||
|
||||
arg = que_node_get_next(arg);
|
||||
}
|
||||
|
||||
data = eval_node_ensure_val_buf(func_node, len);
|
||||
|
||||
arg = func_node->args;
|
||||
len = 0;
|
||||
|
||||
while (arg) {
|
||||
dfield = que_node_get_val(arg);
|
||||
len1 = dfield_get_len(dfield);
|
||||
|
||||
ut_memcpy(data + len, dfield_get_data(dfield), len1);
|
||||
|
||||
len += len1;
|
||||
|
||||
arg = que_node_get_next(arg);
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a predefined function node. If the first argument is an integer,
|
||||
this function looks at the second argument which is the integer length in
|
||||
bytes, and converts the integer to a VARCHAR.
|
||||
If the first argument is of some other type, this function converts it to
|
||||
BINARY. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_to_binary(
|
||||
/*===========*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
que_node_t* arg2;
|
||||
dfield_t* dfield;
|
||||
byte* str1;
|
||||
ulint len;
|
||||
ulint len1;
|
||||
|
||||
arg1 = func_node->args;
|
||||
|
||||
str1 = dfield_get_data(que_node_get_val(arg1));
|
||||
|
||||
if (dtype_get_mtype(que_node_get_data_type(arg1)) != DATA_INT) {
|
||||
|
||||
len = dfield_get_len(que_node_get_val(arg1));
|
||||
|
||||
dfield = que_node_get_val(func_node);
|
||||
|
||||
dfield_set_data(dfield, str1, len);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
arg2 = que_node_get_next(arg1);
|
||||
|
||||
len1 = (ulint)eval_node_get_int_val(arg2);
|
||||
|
||||
if (len1 > 4) {
|
||||
|
||||
ut_error;
|
||||
}
|
||||
|
||||
dfield = que_node_get_val(func_node);
|
||||
|
||||
dfield_set_data(dfield, str1 + (4 - len1), len1);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a predefined function node. */
|
||||
UNIV_INLINE
|
||||
void
|
||||
eval_predefined(
|
||||
/*============*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg1;
|
||||
lint int_val;
|
||||
byte* data;
|
||||
int func;
|
||||
|
||||
func = func_node->func;
|
||||
|
||||
arg1 = func_node->args;
|
||||
|
||||
if (func == PARS_LENGTH_TOKEN) {
|
||||
|
||||
int_val = (lint)dfield_get_len(que_node_get_val(arg1));
|
||||
|
||||
} else if (func == PARS_TO_CHAR_TOKEN) {
|
||||
|
||||
/* Convert number to character string as a
|
||||
signed decimal integer. */
|
||||
|
||||
ulint uint_val;
|
||||
int int_len;
|
||||
|
||||
int_val = eval_node_get_int_val(arg1);
|
||||
|
||||
/* Determine the length of the string. */
|
||||
|
||||
if (int_val == 0) {
|
||||
int_len = 1; /* the number 0 occupies 1 byte */
|
||||
} else {
|
||||
int_len = 0;
|
||||
if (int_val < 0) {
|
||||
uint_val = ((ulint) -int_val - 1) + 1;
|
||||
int_len++; /* reserve space for minus sign */
|
||||
} else {
|
||||
uint_val = (ulint) int_val;
|
||||
}
|
||||
for (; uint_val > 0; int_len++) {
|
||||
uint_val /= 10;
|
||||
}
|
||||
}
|
||||
|
||||
/* allocate the string */
|
||||
data = eval_node_ensure_val_buf(func_node, int_len + 1);
|
||||
|
||||
/* add terminating NUL character */
|
||||
data[int_len] = 0;
|
||||
|
||||
/* convert the number */
|
||||
|
||||
if (int_val == 0) {
|
||||
data[0] = '0';
|
||||
} else {
|
||||
int tmp;
|
||||
if (int_val < 0) {
|
||||
data[0] = '-'; /* preceding minus sign */
|
||||
uint_val = ((ulint) -int_val - 1) + 1;
|
||||
} else {
|
||||
uint_val = (ulint) int_val;
|
||||
}
|
||||
for (tmp = int_len; uint_val > 0; uint_val /= 10) {
|
||||
data[--tmp] = (byte)
|
||||
('0' + (byte)(uint_val % 10));
|
||||
}
|
||||
}
|
||||
|
||||
dfield_set_len(que_node_get_val(func_node), int_len);
|
||||
|
||||
return;
|
||||
|
||||
} else if (func == PARS_TO_NUMBER_TOKEN) {
|
||||
|
||||
int_val = atoi((char*)
|
||||
dfield_get_data(que_node_get_val(arg1)));
|
||||
|
||||
} else if (func == PARS_SYSDATE_TOKEN) {
|
||||
int_val = (lint)ut_time();
|
||||
} else {
|
||||
eval_predefined_2(func_node);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
eval_node_set_int_val(func_node, int_val);
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Evaluates a function node. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
eval_func(
|
||||
/*======*/
|
||||
func_node_t* func_node) /* in: function node */
|
||||
{
|
||||
que_node_t* arg;
|
||||
ulint class;
|
||||
ulint func;
|
||||
|
||||
ut_ad(que_node_get_type(func_node) == QUE_NODE_FUNC);
|
||||
|
||||
class = func_node->class;
|
||||
func = func_node->func;
|
||||
|
||||
arg = func_node->args;
|
||||
|
||||
/* Evaluate first the argument list */
|
||||
while (arg) {
|
||||
eval_exp(arg);
|
||||
|
||||
/* The functions are not defined for SQL null argument
|
||||
values, except for eval_cmp and notfound */
|
||||
|
||||
if (dfield_is_null(que_node_get_val(arg))
|
||||
&& (class != PARS_FUNC_CMP)
|
||||
&& (func != PARS_NOTFOUND_TOKEN)
|
||||
&& (func != PARS_PRINTF_TOKEN)) {
|
||||
ut_error;
|
||||
}
|
||||
|
||||
arg = que_node_get_next(arg);
|
||||
}
|
||||
|
||||
if (class == PARS_FUNC_CMP) {
|
||||
eval_cmp(func_node);
|
||||
} else if (class == PARS_FUNC_ARITH) {
|
||||
eval_arith(func_node);
|
||||
} else if (class == PARS_FUNC_AGGREGATE) {
|
||||
eval_aggregate(func_node);
|
||||
} else if (class == PARS_FUNC_PREDEFINED) {
|
||||
|
||||
if (func == PARS_NOTFOUND_TOKEN) {
|
||||
eval_notfound(func_node);
|
||||
} else if (func == PARS_SUBSTR_TOKEN) {
|
||||
eval_substr(func_node);
|
||||
} else if (func == PARS_REPLSTR_TOKEN) {
|
||||
eval_replstr(func_node);
|
||||
} else if (func == PARS_INSTR_TOKEN) {
|
||||
eval_instr(func_node);
|
||||
} else if (func == PARS_BINARY_TO_NUMBER_TOKEN) {
|
||||
eval_binary_to_number(func_node);
|
||||
} else if (func == PARS_CONCAT_TOKEN) {
|
||||
eval_concat(func_node);
|
||||
} else if (func == PARS_TO_BINARY_TOKEN) {
|
||||
eval_to_binary(func_node);
|
||||
} else {
|
||||
eval_predefined(func_node);
|
||||
}
|
||||
} else {
|
||||
ut_ad(class == PARS_FUNC_LOGICAL);
|
||||
|
||||
eval_logical(func_node);
|
||||
}
|
||||
}
|
||||
294
storage/xtradb/eval/eval0proc.c
Normal file
294
storage/xtradb/eval/eval0proc.c
Normal file
|
|
@ -0,0 +1,294 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1998, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
Executes SQL stored procedures and their control structures
|
||||
|
||||
Created 1/20/1998 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "eval0proc.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "eval0proc.ic"
|
||||
#endif
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of an if-statement node. */
|
||||
UNIV_INTERN
|
||||
que_thr_t*
|
||||
if_step(
|
||||
/*====*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
if_node_t* node;
|
||||
elsif_node_t* elsif_node;
|
||||
|
||||
ut_ad(thr);
|
||||
|
||||
node = thr->run_node;
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_IF);
|
||||
|
||||
if (thr->prev_node == que_node_get_parent(node)) {
|
||||
|
||||
/* Evaluate the condition */
|
||||
|
||||
eval_exp(node->cond);
|
||||
|
||||
if (eval_node_get_ibool_val(node->cond)) {
|
||||
|
||||
/* The condition evaluated to TRUE: start execution
|
||||
from the first statement in the statement list */
|
||||
|
||||
thr->run_node = node->stat_list;
|
||||
|
||||
} else if (node->else_part) {
|
||||
thr->run_node = node->else_part;
|
||||
|
||||
} else if (node->elsif_list) {
|
||||
elsif_node = node->elsif_list;
|
||||
|
||||
for (;;) {
|
||||
eval_exp(elsif_node->cond);
|
||||
|
||||
if (eval_node_get_ibool_val(
|
||||
elsif_node->cond)) {
|
||||
|
||||
/* The condition evaluated to TRUE:
|
||||
start execution from the first
|
||||
statement in the statement list */
|
||||
|
||||
thr->run_node = elsif_node->stat_list;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
elsif_node = que_node_get_next(elsif_node);
|
||||
|
||||
if (elsif_node == NULL) {
|
||||
thr->run_node = NULL;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
thr->run_node = NULL;
|
||||
}
|
||||
} else {
|
||||
/* Move to the next statement */
|
||||
ut_ad(que_node_get_next(thr->prev_node) == NULL);
|
||||
|
||||
thr->run_node = NULL;
|
||||
}
|
||||
|
||||
if (thr->run_node == NULL) {
|
||||
thr->run_node = que_node_get_parent(node);
|
||||
}
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of a while-statement node. */
|
||||
UNIV_INTERN
|
||||
que_thr_t*
|
||||
while_step(
|
||||
/*=======*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
while_node_t* node;
|
||||
|
||||
ut_ad(thr);
|
||||
|
||||
node = thr->run_node;
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_WHILE);
|
||||
|
||||
ut_ad((thr->prev_node == que_node_get_parent(node))
|
||||
|| (que_node_get_next(thr->prev_node) == NULL));
|
||||
|
||||
/* Evaluate the condition */
|
||||
|
||||
eval_exp(node->cond);
|
||||
|
||||
if (eval_node_get_ibool_val(node->cond)) {
|
||||
|
||||
/* The condition evaluated to TRUE: start execution
|
||||
from the first statement in the statement list */
|
||||
|
||||
thr->run_node = node->stat_list;
|
||||
} else {
|
||||
thr->run_node = que_node_get_parent(node);
|
||||
}
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of an assignment statement node. */
|
||||
UNIV_INTERN
|
||||
que_thr_t*
|
||||
assign_step(
|
||||
/*========*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
assign_node_t* node;
|
||||
|
||||
ut_ad(thr);
|
||||
|
||||
node = thr->run_node;
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_ASSIGNMENT);
|
||||
|
||||
/* Evaluate the value to assign */
|
||||
|
||||
eval_exp(node->val);
|
||||
|
||||
eval_node_copy_val(node->var->alias, node->val);
|
||||
|
||||
thr->run_node = que_node_get_parent(node);
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of a for-loop node. */
|
||||
UNIV_INTERN
|
||||
que_thr_t*
|
||||
for_step(
|
||||
/*=====*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
for_node_t* node;
|
||||
que_node_t* parent;
|
||||
lint loop_var_value;
|
||||
|
||||
ut_ad(thr);
|
||||
|
||||
node = thr->run_node;
|
||||
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_FOR);
|
||||
|
||||
parent = que_node_get_parent(node);
|
||||
|
||||
if (thr->prev_node != parent) {
|
||||
|
||||
/* Move to the next statement */
|
||||
thr->run_node = que_node_get_next(thr->prev_node);
|
||||
|
||||
if (thr->run_node != NULL) {
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/* Increment the value of loop_var */
|
||||
|
||||
loop_var_value = 1 + eval_node_get_int_val(node->loop_var);
|
||||
} else {
|
||||
/* Initialize the loop */
|
||||
|
||||
eval_exp(node->loop_start_limit);
|
||||
eval_exp(node->loop_end_limit);
|
||||
|
||||
loop_var_value = eval_node_get_int_val(node->loop_start_limit);
|
||||
|
||||
node->loop_end_value
|
||||
= (int) eval_node_get_int_val(node->loop_end_limit);
|
||||
}
|
||||
|
||||
/* Check if we should do another loop */
|
||||
|
||||
if (loop_var_value > node->loop_end_value) {
|
||||
|
||||
/* Enough loops done */
|
||||
|
||||
thr->run_node = parent;
|
||||
} else {
|
||||
eval_node_set_int_val(node->loop_var, loop_var_value);
|
||||
|
||||
thr->run_node = node->stat_list;
|
||||
}
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of an exit statement node. */
|
||||
UNIV_INTERN
|
||||
que_thr_t*
|
||||
exit_step(
|
||||
/*======*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
exit_node_t* node;
|
||||
que_node_t* loop_node;
|
||||
|
||||
ut_ad(thr);
|
||||
|
||||
node = thr->run_node;
|
||||
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_EXIT);
|
||||
|
||||
/* Loops exit by setting thr->run_node as the loop node's parent, so
|
||||
find our containing loop node and get its parent. */
|
||||
|
||||
loop_node = que_node_get_containing_loop_node(node);
|
||||
|
||||
/* If someone uses an EXIT statement outside of a loop, this will
|
||||
trigger. */
|
||||
ut_a(loop_node);
|
||||
|
||||
thr->run_node = que_node_get_parent(loop_node);
|
||||
|
||||
return(thr);
|
||||
}
|
||||
|
||||
/**************************************************************************
|
||||
Performs an execution step of a return-statement node. */
|
||||
UNIV_INTERN
|
||||
que_thr_t*
|
||||
return_step(
|
||||
/*========*/
|
||||
/* out: query thread to run next or NULL */
|
||||
que_thr_t* thr) /* in: query thread */
|
||||
{
|
||||
return_node_t* node;
|
||||
que_node_t* parent;
|
||||
|
||||
ut_ad(thr);
|
||||
|
||||
node = thr->run_node;
|
||||
|
||||
ut_ad(que_node_get_type(node) == QUE_NODE_RETURN);
|
||||
|
||||
parent = node;
|
||||
|
||||
while (que_node_get_type(parent) != QUE_NODE_PROC) {
|
||||
|
||||
parent = que_node_get_parent(parent);
|
||||
}
|
||||
|
||||
ut_a(parent);
|
||||
|
||||
thr->run_node = que_node_get_parent(parent);
|
||||
|
||||
return(thr);
|
||||
}
|
||||
5090
storage/xtradb/fil/fil0fil.c
Normal file
5090
storage/xtradb/fil/fil0fil.c
Normal file
File diff suppressed because it is too large
Load diff
4284
storage/xtradb/fsp/fsp0fsp.c
Normal file
4284
storage/xtradb/fsp/fsp0fsp.c
Normal file
File diff suppressed because it is too large
Load diff
30
storage/xtradb/fut/fut0fut.c
Normal file
30
storage/xtradb/fut/fut0fut.c
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
File-based utilities
|
||||
|
||||
Created 12/13/1995 Heikki Tuuri
|
||||
***********************************************************************/
|
||||
|
||||
#include "fut0fut.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "fut0fut.ic"
|
||||
#endif
|
||||
|
||||
529
storage/xtradb/fut/fut0lst.c
Normal file
529
storage/xtradb/fut/fut0lst.c
Normal file
|
|
@ -0,0 +1,529 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1995, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
File-based list utilities
|
||||
|
||||
Created 11/28/1995 Heikki Tuuri
|
||||
***********************************************************************/
|
||||
|
||||
#include "fut0lst.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "fut0lst.ic"
|
||||
#endif
|
||||
|
||||
#include "buf0buf.h"
|
||||
#include "page0page.h"
|
||||
|
||||
/************************************************************************
|
||||
Adds a node to an empty list. */
|
||||
static
|
||||
void
|
||||
flst_add_to_empty(
|
||||
/*==============*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of
|
||||
empty list */
|
||||
flst_node_t* node, /* in: node to add */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
ulint space;
|
||||
fil_addr_t node_addr;
|
||||
ulint len;
|
||||
|
||||
ut_ad(mtr && base && node);
|
||||
ut_ad(base != node);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
|
||||
len = flst_get_len(base, mtr);
|
||||
ut_a(len == 0);
|
||||
|
||||
buf_ptr_get_fsp_addr(node, &space, &node_addr);
|
||||
|
||||
/* Update first and last fields of base node */
|
||||
flst_write_addr(base + FLST_FIRST, node_addr, mtr);
|
||||
flst_write_addr(base + FLST_LAST, node_addr, mtr);
|
||||
|
||||
/* Set prev and next fields of node to add */
|
||||
flst_write_addr(node + FLST_PREV, fil_addr_null, mtr);
|
||||
flst_write_addr(node + FLST_NEXT, fil_addr_null, mtr);
|
||||
|
||||
/* Update len of base node */
|
||||
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Adds a node as the last node in a list. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_add_last(
|
||||
/*==========*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
flst_node_t* node, /* in: node to add */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
ulint space;
|
||||
fil_addr_t node_addr;
|
||||
ulint len;
|
||||
fil_addr_t last_addr;
|
||||
flst_node_t* last_node;
|
||||
|
||||
ut_ad(mtr && base && node);
|
||||
ut_ad(base != node);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
|
||||
len = flst_get_len(base, mtr);
|
||||
last_addr = flst_get_last(base, mtr);
|
||||
|
||||
buf_ptr_get_fsp_addr(node, &space, &node_addr);
|
||||
|
||||
/* If the list is not empty, call flst_insert_after */
|
||||
if (len != 0) {
|
||||
if (last_addr.page == node_addr.page) {
|
||||
last_node = page_align(node) + last_addr.boffset;
|
||||
} else {
|
||||
ulint zip_size = fil_space_get_zip_size(space);
|
||||
|
||||
last_node = fut_get_ptr(space, zip_size, last_addr,
|
||||
RW_X_LATCH, mtr);
|
||||
}
|
||||
|
||||
flst_insert_after(base, last_node, node, mtr);
|
||||
} else {
|
||||
/* else call flst_add_to_empty */
|
||||
flst_add_to_empty(base, node, mtr);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Adds a node as the first node in a list. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_add_first(
|
||||
/*===========*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
flst_node_t* node, /* in: node to add */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
ulint space;
|
||||
fil_addr_t node_addr;
|
||||
ulint len;
|
||||
fil_addr_t first_addr;
|
||||
flst_node_t* first_node;
|
||||
|
||||
ut_ad(mtr && base && node);
|
||||
ut_ad(base != node);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node, MTR_MEMO_PAGE_X_FIX));
|
||||
len = flst_get_len(base, mtr);
|
||||
first_addr = flst_get_first(base, mtr);
|
||||
|
||||
buf_ptr_get_fsp_addr(node, &space, &node_addr);
|
||||
|
||||
/* If the list is not empty, call flst_insert_before */
|
||||
if (len != 0) {
|
||||
if (first_addr.page == node_addr.page) {
|
||||
first_node = page_align(node) + first_addr.boffset;
|
||||
} else {
|
||||
ulint zip_size = fil_space_get_zip_size(space);
|
||||
|
||||
first_node = fut_get_ptr(space, zip_size, first_addr,
|
||||
RW_X_LATCH, mtr);
|
||||
}
|
||||
|
||||
flst_insert_before(base, node, first_node, mtr);
|
||||
} else {
|
||||
/* else call flst_add_to_empty */
|
||||
flst_add_to_empty(base, node, mtr);
|
||||
}
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Inserts a node after another in a list. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_insert_after(
|
||||
/*==============*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
flst_node_t* node1, /* in: node to insert after */
|
||||
flst_node_t* node2, /* in: node to add */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
ulint space;
|
||||
fil_addr_t node1_addr;
|
||||
fil_addr_t node2_addr;
|
||||
flst_node_t* node3;
|
||||
fil_addr_t node3_addr;
|
||||
ulint len;
|
||||
|
||||
ut_ad(mtr && node1 && node2 && base);
|
||||
ut_ad(base != node1);
|
||||
ut_ad(base != node2);
|
||||
ut_ad(node2 != node1);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node1, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
buf_ptr_get_fsp_addr(node1, &space, &node1_addr);
|
||||
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
|
||||
|
||||
node3_addr = flst_get_next_addr(node1, mtr);
|
||||
|
||||
/* Set prev and next fields of node2 */
|
||||
flst_write_addr(node2 + FLST_PREV, node1_addr, mtr);
|
||||
flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr);
|
||||
|
||||
if (!fil_addr_is_null(node3_addr)) {
|
||||
/* Update prev field of node3 */
|
||||
ulint zip_size = fil_space_get_zip_size(space);
|
||||
|
||||
node3 = fut_get_ptr(space, zip_size,
|
||||
node3_addr, RW_X_LATCH, mtr);
|
||||
flst_write_addr(node3 + FLST_PREV, node2_addr, mtr);
|
||||
} else {
|
||||
/* node1 was last in list: update last field in base */
|
||||
flst_write_addr(base + FLST_LAST, node2_addr, mtr);
|
||||
}
|
||||
|
||||
/* Set next field of node1 */
|
||||
flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr);
|
||||
|
||||
/* Update len of base node */
|
||||
len = flst_get_len(base, mtr);
|
||||
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Inserts a node before another in a list. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_insert_before(
|
||||
/*===============*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
flst_node_t* node2, /* in: node to insert */
|
||||
flst_node_t* node3, /* in: node to insert before */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
ulint space;
|
||||
flst_node_t* node1;
|
||||
fil_addr_t node1_addr;
|
||||
fil_addr_t node2_addr;
|
||||
fil_addr_t node3_addr;
|
||||
ulint len;
|
||||
|
||||
ut_ad(mtr && node2 && node3 && base);
|
||||
ut_ad(base != node2);
|
||||
ut_ad(base != node3);
|
||||
ut_ad(node2 != node3);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node3, MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
|
||||
buf_ptr_get_fsp_addr(node3, &space, &node3_addr);
|
||||
|
||||
node1_addr = flst_get_prev_addr(node3, mtr);
|
||||
|
||||
/* Set prev and next fields of node2 */
|
||||
flst_write_addr(node2 + FLST_PREV, node1_addr, mtr);
|
||||
flst_write_addr(node2 + FLST_NEXT, node3_addr, mtr);
|
||||
|
||||
if (!fil_addr_is_null(node1_addr)) {
|
||||
ulint zip_size = fil_space_get_zip_size(space);
|
||||
/* Update next field of node1 */
|
||||
node1 = fut_get_ptr(space, zip_size, node1_addr,
|
||||
RW_X_LATCH, mtr);
|
||||
flst_write_addr(node1 + FLST_NEXT, node2_addr, mtr);
|
||||
} else {
|
||||
/* node3 was first in list: update first field in base */
|
||||
flst_write_addr(base + FLST_FIRST, node2_addr, mtr);
|
||||
}
|
||||
|
||||
/* Set prev field of node3 */
|
||||
flst_write_addr(node3 + FLST_PREV, node2_addr, mtr);
|
||||
|
||||
/* Update len of base node */
|
||||
len = flst_get_len(base, mtr);
|
||||
mlog_write_ulint(base + FLST_LEN, len + 1, MLOG_4BYTES, mtr);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Removes a node. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_remove(
|
||||
/*========*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
flst_node_t* node2, /* in: node to remove */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
ulint space;
|
||||
ulint zip_size;
|
||||
flst_node_t* node1;
|
||||
fil_addr_t node1_addr;
|
||||
fil_addr_t node2_addr;
|
||||
flst_node_t* node3;
|
||||
fil_addr_t node3_addr;
|
||||
ulint len;
|
||||
|
||||
ut_ad(mtr && node2 && base);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
|
||||
zip_size = fil_space_get_zip_size(space);
|
||||
|
||||
node1_addr = flst_get_prev_addr(node2, mtr);
|
||||
node3_addr = flst_get_next_addr(node2, mtr);
|
||||
|
||||
if (!fil_addr_is_null(node1_addr)) {
|
||||
|
||||
/* Update next field of node1 */
|
||||
|
||||
if (node1_addr.page == node2_addr.page) {
|
||||
|
||||
node1 = page_align(node2) + node1_addr.boffset;
|
||||
} else {
|
||||
node1 = fut_get_ptr(space, zip_size,
|
||||
node1_addr, RW_X_LATCH, mtr);
|
||||
}
|
||||
|
||||
ut_ad(node1 != node2);
|
||||
|
||||
flst_write_addr(node1 + FLST_NEXT, node3_addr, mtr);
|
||||
} else {
|
||||
/* node2 was first in list: update first field in base */
|
||||
flst_write_addr(base + FLST_FIRST, node3_addr, mtr);
|
||||
}
|
||||
|
||||
if (!fil_addr_is_null(node3_addr)) {
|
||||
/* Update prev field of node3 */
|
||||
|
||||
if (node3_addr.page == node2_addr.page) {
|
||||
|
||||
node3 = page_align(node2) + node3_addr.boffset;
|
||||
} else {
|
||||
node3 = fut_get_ptr(space, zip_size,
|
||||
node3_addr, RW_X_LATCH, mtr);
|
||||
}
|
||||
|
||||
ut_ad(node2 != node3);
|
||||
|
||||
flst_write_addr(node3 + FLST_PREV, node1_addr, mtr);
|
||||
} else {
|
||||
/* node2 was last in list: update last field in base */
|
||||
flst_write_addr(base + FLST_LAST, node1_addr, mtr);
|
||||
}
|
||||
|
||||
/* Update len of base node */
|
||||
len = flst_get_len(base, mtr);
|
||||
ut_ad(len > 0);
|
||||
|
||||
mlog_write_ulint(base + FLST_LEN, len - 1, MLOG_4BYTES, mtr);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Cuts off the tail of the list, including the node given. The number of
|
||||
nodes which will be removed must be provided by the caller, as this function
|
||||
does not measure the length of the tail. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_cut_end(
|
||||
/*=========*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
flst_node_t* node2, /* in: first node to remove */
|
||||
ulint n_nodes,/* in: number of nodes to remove,
|
||||
must be >= 1 */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
ulint space;
|
||||
flst_node_t* node1;
|
||||
fil_addr_t node1_addr;
|
||||
fil_addr_t node2_addr;
|
||||
ulint len;
|
||||
|
||||
ut_ad(mtr && node2 && base);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(n_nodes > 0);
|
||||
|
||||
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
|
||||
|
||||
node1_addr = flst_get_prev_addr(node2, mtr);
|
||||
|
||||
if (!fil_addr_is_null(node1_addr)) {
|
||||
|
||||
/* Update next field of node1 */
|
||||
|
||||
if (node1_addr.page == node2_addr.page) {
|
||||
|
||||
node1 = page_align(node2) + node1_addr.boffset;
|
||||
} else {
|
||||
node1 = fut_get_ptr(space,
|
||||
fil_space_get_zip_size(space),
|
||||
node1_addr, RW_X_LATCH, mtr);
|
||||
}
|
||||
|
||||
flst_write_addr(node1 + FLST_NEXT, fil_addr_null, mtr);
|
||||
} else {
|
||||
/* node2 was first in list: update the field in base */
|
||||
flst_write_addr(base + FLST_FIRST, fil_addr_null, mtr);
|
||||
}
|
||||
|
||||
flst_write_addr(base + FLST_LAST, node1_addr, mtr);
|
||||
|
||||
/* Update len of base node */
|
||||
len = flst_get_len(base, mtr);
|
||||
ut_ad(len >= n_nodes);
|
||||
|
||||
mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Cuts off the tail of the list, not including the given node. The number of
|
||||
nodes which will be removed must be provided by the caller, as this function
|
||||
does not measure the length of the tail. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_truncate_end(
|
||||
/*==============*/
|
||||
flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
flst_node_t* node2, /* in: first node not to remove */
|
||||
ulint n_nodes,/* in: number of nodes to remove */
|
||||
mtr_t* mtr) /* in: mini-transaction handle */
|
||||
{
|
||||
fil_addr_t node2_addr;
|
||||
ulint len;
|
||||
ulint space;
|
||||
|
||||
ut_ad(mtr && node2 && base);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
ut_ad(mtr_memo_contains_page(mtr, node2, MTR_MEMO_PAGE_X_FIX));
|
||||
if (n_nodes == 0) {
|
||||
|
||||
ut_ad(fil_addr_is_null(flst_get_next_addr(node2, mtr)));
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
buf_ptr_get_fsp_addr(node2, &space, &node2_addr);
|
||||
|
||||
/* Update next field of node2 */
|
||||
flst_write_addr(node2 + FLST_NEXT, fil_addr_null, mtr);
|
||||
|
||||
flst_write_addr(base + FLST_LAST, node2_addr, mtr);
|
||||
|
||||
/* Update len of base node */
|
||||
len = flst_get_len(base, mtr);
|
||||
ut_ad(len >= n_nodes);
|
||||
|
||||
mlog_write_ulint(base + FLST_LEN, len - n_nodes, MLOG_4BYTES, mtr);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Validates a file-based list. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
flst_validate(
|
||||
/*==========*/
|
||||
/* out: TRUE if ok */
|
||||
const flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
mtr_t* mtr1) /* in: mtr */
|
||||
{
|
||||
ulint space;
|
||||
ulint zip_size;
|
||||
const flst_node_t* node;
|
||||
fil_addr_t node_addr;
|
||||
fil_addr_t base_addr;
|
||||
ulint len;
|
||||
ulint i;
|
||||
mtr_t mtr2;
|
||||
|
||||
ut_ad(base);
|
||||
ut_ad(mtr_memo_contains_page(mtr1, base, MTR_MEMO_PAGE_X_FIX));
|
||||
|
||||
/* We use two mini-transaction handles: the first is used to
|
||||
lock the base node, and prevent other threads from modifying the
|
||||
list. The second is used to traverse the list. We cannot run the
|
||||
second mtr without committing it at times, because if the list
|
||||
is long, then the x-locked pages could fill the buffer resulting
|
||||
in a deadlock. */
|
||||
|
||||
/* Find out the space id */
|
||||
buf_ptr_get_fsp_addr(base, &space, &base_addr);
|
||||
zip_size = fil_space_get_zip_size(space);
|
||||
|
||||
len = flst_get_len(base, mtr1);
|
||||
node_addr = flst_get_first(base, mtr1);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
mtr_start(&mtr2);
|
||||
|
||||
node = fut_get_ptr(space, zip_size,
|
||||
node_addr, RW_X_LATCH, &mtr2);
|
||||
node_addr = flst_get_next_addr(node, &mtr2);
|
||||
|
||||
mtr_commit(&mtr2); /* Commit mtr2 each round to prevent buffer
|
||||
becoming full */
|
||||
}
|
||||
|
||||
ut_a(fil_addr_is_null(node_addr));
|
||||
|
||||
node_addr = flst_get_last(base, mtr1);
|
||||
|
||||
for (i = 0; i < len; i++) {
|
||||
mtr_start(&mtr2);
|
||||
|
||||
node = fut_get_ptr(space, zip_size,
|
||||
node_addr, RW_X_LATCH, &mtr2);
|
||||
node_addr = flst_get_prev_addr(node, &mtr2);
|
||||
|
||||
mtr_commit(&mtr2); /* Commit mtr2 each round to prevent buffer
|
||||
becoming full */
|
||||
}
|
||||
|
||||
ut_a(fil_addr_is_null(node_addr));
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/************************************************************************
|
||||
Prints info of a file-based list. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
flst_print(
|
||||
/*=======*/
|
||||
const flst_base_node_t* base, /* in: pointer to base node of list */
|
||||
mtr_t* mtr) /* in: mtr */
|
||||
{
|
||||
const buf_frame_t* frame;
|
||||
ulint len;
|
||||
|
||||
ut_ad(base && mtr);
|
||||
ut_ad(mtr_memo_contains_page(mtr, base, MTR_MEMO_PAGE_X_FIX));
|
||||
frame = page_align((byte*) base);
|
||||
|
||||
len = flst_get_len(base, mtr);
|
||||
|
||||
fprintf(stderr,
|
||||
"FILE-BASED LIST:\n"
|
||||
"Base node in space %lu page %lu byte offset %lu; len %lu\n",
|
||||
(ulong) page_get_space_id(frame),
|
||||
(ulong) page_get_page_no(frame),
|
||||
(ulong) page_offset(base), (ulong) len);
|
||||
}
|
||||
442
storage/xtradb/ha/ha0ha.c
Normal file
442
storage/xtradb/ha/ha0ha.c
Normal file
|
|
@ -0,0 +1,442 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1994, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/************************************************************************
|
||||
The hash table with external chains
|
||||
|
||||
Created 8/22/1994 Heikki Tuuri
|
||||
*************************************************************************/
|
||||
|
||||
#include "ha0ha.h"
|
||||
#ifdef UNIV_NONINL
|
||||
#include "ha0ha.ic"
|
||||
#endif
|
||||
|
||||
#ifdef UNIV_DEBUG
|
||||
# include "buf0buf.h"
|
||||
#endif /* UNIV_DEBUG */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
# include "btr0sea.h"
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
#include "page0page.h"
|
||||
|
||||
/*****************************************************************
|
||||
Creates a hash table with >= n array cells. The actual number of cells is
|
||||
chosen to be a prime number slightly bigger than n. */
|
||||
UNIV_INTERN
|
||||
hash_table_t*
|
||||
ha_create_func(
|
||||
/*===========*/
|
||||
/* out, own: created table */
|
||||
ulint n, /* in: number of array cells */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ulint mutex_level, /* in: level of the mutexes in the latching
|
||||
order: this is used in the debug version */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ulint n_mutexes) /* in: number of mutexes to protect the
|
||||
hash table: must be a power of 2, or 0 */
|
||||
{
|
||||
hash_table_t* table;
|
||||
ulint i;
|
||||
|
||||
table = hash_create(n);
|
||||
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
table->adaptive = TRUE;
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
/* Creating MEM_HEAP_BTR_SEARCH type heaps can potentially fail,
|
||||
but in practise it never should in this case, hence the asserts. */
|
||||
|
||||
if (n_mutexes == 0) {
|
||||
table->heap = mem_heap_create_in_btr_search(
|
||||
ut_min(4096, MEM_MAX_ALLOC_IN_BUF));
|
||||
ut_a(table->heap);
|
||||
|
||||
return(table);
|
||||
}
|
||||
|
||||
hash_create_mutexes(table, n_mutexes, mutex_level);
|
||||
|
||||
table->heaps = mem_alloc(n_mutexes * sizeof(void*));
|
||||
|
||||
for (i = 0; i < n_mutexes; i++) {
|
||||
table->heaps[i] = mem_heap_create_in_btr_search(4096);
|
||||
ut_a(table->heaps[i]);
|
||||
}
|
||||
|
||||
return(table);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Empties a hash table and frees the memory heaps. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ha_clear(
|
||||
/*=====*/
|
||||
hash_table_t* table) /* in, own: hash table */
|
||||
{
|
||||
ulint i;
|
||||
ulint n;
|
||||
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ut_ad(rw_lock_own(&btr_search_latch, RW_LOCK_EXCLUSIVE));
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
|
||||
/* Free the memory heaps. */
|
||||
n = table->n_mutexes;
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
mem_heap_free(table->heaps[i]);
|
||||
}
|
||||
|
||||
/* Clear the hash table. */
|
||||
n = hash_get_n_cells(table);
|
||||
|
||||
for (i = 0; i < n; i++) {
|
||||
hash_get_nth_cell(table, i)->node = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Inserts an entry into a hash table. If an entry with the same fold number
|
||||
is found, its node is updated to point to the new data, and no new node
|
||||
is inserted. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
ha_insert_for_fold_func(
|
||||
/*====================*/
|
||||
/* out: TRUE if succeed, FALSE if no more
|
||||
memory could be allocated */
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ulint fold, /* in: folded value of data; if a node with
|
||||
the same fold value already exists, it is
|
||||
updated to point to the same data, and no new
|
||||
node is created! */
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
buf_block_t* block, /* in: buffer block containing the data */
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
void* data) /* in: data, must not be NULL */
|
||||
{
|
||||
hash_cell_t* cell;
|
||||
ha_node_t* node;
|
||||
ha_node_t* prev_node;
|
||||
ulint hash;
|
||||
|
||||
ut_ad(table && data);
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
ut_a(block->frame == page_align(data));
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
|
||||
|
||||
hash = hash_calc_hash(fold, table);
|
||||
|
||||
cell = hash_get_nth_cell(table, hash);
|
||||
|
||||
prev_node = cell->node;
|
||||
|
||||
while (prev_node != NULL) {
|
||||
if (prev_node->fold == fold) {
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
if (table->adaptive) {
|
||||
buf_block_t* prev_block = prev_node->block;
|
||||
ut_a(prev_block->frame
|
||||
== page_align(prev_node->data));
|
||||
ut_a(prev_block->n_pointers > 0);
|
||||
prev_block->n_pointers--;
|
||||
block->n_pointers++;
|
||||
}
|
||||
|
||||
prev_node->block = block;
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
prev_node->data = data;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
prev_node = prev_node->next;
|
||||
}
|
||||
|
||||
/* We have to allocate a new chain node */
|
||||
|
||||
node = mem_heap_alloc(hash_get_heap(table, fold), sizeof(ha_node_t));
|
||||
|
||||
if (node == NULL) {
|
||||
/* It was a btr search type memory heap and at the moment
|
||||
no more memory could be allocated: return */
|
||||
|
||||
ut_ad(hash_get_heap(table, fold)->type & MEM_HEAP_BTR_SEARCH);
|
||||
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
ha_node_set_data(node, block, data);
|
||||
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
if (table->adaptive) {
|
||||
block->n_pointers++;
|
||||
}
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
node->fold = fold;
|
||||
|
||||
node->next = NULL;
|
||||
|
||||
prev_node = cell->node;
|
||||
|
||||
if (prev_node == NULL) {
|
||||
|
||||
cell->node = node;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
while (prev_node->next != NULL) {
|
||||
|
||||
prev_node = prev_node->next;
|
||||
}
|
||||
|
||||
prev_node->next = node;
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
/***************************************************************
|
||||
Deletes a hash node. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ha_delete_hash_node(
|
||||
/*================*/
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ha_node_t* del_node) /* in: node to be deleted */
|
||||
{
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
if (table->adaptive) {
|
||||
ut_a(del_node->block->frame = page_align(del_node->data));
|
||||
ut_a(del_node->block->n_pointers > 0);
|
||||
del_node->block->n_pointers--;
|
||||
}
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
HASH_DELETE_AND_COMPACT(ha_node_t, next, table, del_node);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Deletes an entry from a hash table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ha_delete(
|
||||
/*======*/
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ulint fold, /* in: folded value of data */
|
||||
void* data) /* in: data, must not be NULL and must exist
|
||||
in the hash table */
|
||||
{
|
||||
ha_node_t* node;
|
||||
|
||||
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
|
||||
|
||||
node = ha_search_with_data(table, fold, data);
|
||||
|
||||
ut_a(node);
|
||||
|
||||
ha_delete_hash_node(table, node);
|
||||
}
|
||||
|
||||
/*************************************************************
|
||||
Looks for an element when we know the pointer to the data, and updates
|
||||
the pointer to data, if found. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ha_search_and_update_if_found_func(
|
||||
/*===============================*/
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ulint fold, /* in: folded value of the searched data */
|
||||
void* data, /* in: pointer to the data */
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
buf_block_t* new_block,/* in: block containing new_data */
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
void* new_data)/* in: new pointer to the data */
|
||||
{
|
||||
ha_node_t* node;
|
||||
|
||||
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
ut_a(new_block->frame == page_align(new_data));
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
|
||||
node = ha_search_with_data(table, fold, data);
|
||||
|
||||
if (node) {
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
if (table->adaptive) {
|
||||
ut_a(node->block->n_pointers > 0);
|
||||
node->block->n_pointers--;
|
||||
new_block->n_pointers++;
|
||||
}
|
||||
|
||||
node->block = new_block;
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
node->data = new_data;
|
||||
}
|
||||
}
|
||||
|
||||
/*********************************************************************
|
||||
Removes from the chain determined by fold all nodes whose data pointer
|
||||
points to the page given. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ha_remove_all_nodes_to_page(
|
||||
/*========================*/
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ulint fold, /* in: fold value */
|
||||
const page_t* page) /* in: buffer page */
|
||||
{
|
||||
ha_node_t* node;
|
||||
|
||||
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
|
||||
|
||||
node = ha_chain_get_first(table, fold);
|
||||
|
||||
while (node) {
|
||||
if (page_align(ha_node_get_data(node)) == page) {
|
||||
|
||||
/* Remove the hash node */
|
||||
|
||||
ha_delete_hash_node(table, node);
|
||||
|
||||
/* Start again from the first node in the chain
|
||||
because the deletion may compact the heap of
|
||||
nodes and move other nodes! */
|
||||
|
||||
node = ha_chain_get_first(table, fold);
|
||||
} else {
|
||||
node = ha_chain_get_next(node);
|
||||
}
|
||||
}
|
||||
#ifdef UNIV_DEBUG
|
||||
/* Check that all nodes really got deleted */
|
||||
|
||||
node = ha_chain_get_first(table, fold);
|
||||
|
||||
while (node) {
|
||||
ut_a(page_align(ha_node_get_data(node)) != page);
|
||||
|
||||
node = ha_chain_get_next(node);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Validates a given range of the cells in hash table. */
|
||||
UNIV_INTERN
|
||||
ibool
|
||||
ha_validate(
|
||||
/*========*/
|
||||
/* out: TRUE if ok */
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ulint start_index, /* in: start index */
|
||||
ulint end_index) /* in: end index */
|
||||
{
|
||||
hash_cell_t* cell;
|
||||
ha_node_t* node;
|
||||
ibool ok = TRUE;
|
||||
ulint i;
|
||||
|
||||
ut_a(start_index <= end_index);
|
||||
ut_a(start_index < hash_get_n_cells(table));
|
||||
ut_a(end_index < hash_get_n_cells(table));
|
||||
|
||||
for (i = start_index; i <= end_index; i++) {
|
||||
|
||||
cell = hash_get_nth_cell(table, i);
|
||||
|
||||
node = cell->node;
|
||||
|
||||
while (node) {
|
||||
if (hash_calc_hash(node->fold, table) != i) {
|
||||
ut_print_timestamp(stderr);
|
||||
fprintf(stderr,
|
||||
"InnoDB: Error: hash table node"
|
||||
" fold value %lu does not\n"
|
||||
"InnoDB: match the cell number %lu.\n",
|
||||
(ulong) node->fold, (ulong) i);
|
||||
|
||||
ok = FALSE;
|
||||
}
|
||||
|
||||
node = node->next;
|
||||
}
|
||||
}
|
||||
|
||||
return(ok);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Prints info of a hash table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
ha_print_info(
|
||||
/*==========*/
|
||||
FILE* file, /* in: file where to print */
|
||||
hash_table_t* table) /* in: hash table */
|
||||
{
|
||||
#ifdef UNIV_DEBUG
|
||||
/* Some of the code here is disabled for performance reasons in production
|
||||
builds, see http://bugs.mysql.com/36941 */
|
||||
#define PRINT_USED_CELLS
|
||||
#endif /* UNIV_DEBUG */
|
||||
|
||||
#ifdef PRINT_USED_CELLS
|
||||
hash_cell_t* cell;
|
||||
ulint cells = 0;
|
||||
ulint i;
|
||||
#endif /* PRINT_USED_CELLS */
|
||||
ulint n_bufs;
|
||||
|
||||
#ifdef PRINT_USED_CELLS
|
||||
for (i = 0; i < hash_get_n_cells(table); i++) {
|
||||
|
||||
cell = hash_get_nth_cell(table, i);
|
||||
|
||||
if (cell->node) {
|
||||
|
||||
cells++;
|
||||
}
|
||||
}
|
||||
#endif /* PRINT_USED_CELLS */
|
||||
|
||||
fprintf(file, "Hash table size %lu",
|
||||
(ulong) hash_get_n_cells(table));
|
||||
|
||||
#ifdef PRINT_USED_CELLS
|
||||
fprintf(file, ", used cells %lu", (ulong) cells);
|
||||
#endif /* PRINT_USED_CELLS */
|
||||
|
||||
if (table->heaps == NULL && table->heap != NULL) {
|
||||
|
||||
/* This calculation is intended for the adaptive hash
|
||||
index: how many buffer frames we have reserved? */
|
||||
|
||||
n_bufs = UT_LIST_GET_LEN(table->heap->base) - 1;
|
||||
|
||||
if (table->heap->free_block) {
|
||||
n_bufs++;
|
||||
}
|
||||
|
||||
fprintf(file, ", node heap has %lu buffer(s)\n",
|
||||
(ulong) n_bufs);
|
||||
}
|
||||
}
|
||||
183
storage/xtradb/ha/ha0storage.c
Normal file
183
storage/xtradb/ha/ha0storage.c
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 2007, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
Hash storage.
|
||||
Provides a data structure that stores chunks of data in
|
||||
its own storage, avoiding duplicates.
|
||||
|
||||
Created September 22, 2007 Vasil Dimov
|
||||
*******************************************************/
|
||||
|
||||
#include "univ.i"
|
||||
#include "ha0storage.h"
|
||||
#include "hash0hash.h"
|
||||
#include "mem0mem.h"
|
||||
#include "ut0rnd.h"
|
||||
|
||||
#ifdef UNIV_NONINL
|
||||
#include "ha0storage.ic"
|
||||
#endif
|
||||
|
||||
/***********************************************************************
|
||||
Retrieves a data from a storage. If it is present, a pointer to the
|
||||
stored copy of data is returned, otherwise NULL is returned. */
|
||||
static
|
||||
const void*
|
||||
ha_storage_get(
|
||||
/*===========*/
|
||||
ha_storage_t* storage, /* in: hash storage */
|
||||
const void* data, /* in: data to check for */
|
||||
ulint data_len) /* in: data length */
|
||||
{
|
||||
ha_storage_node_t* node;
|
||||
ulint fold;
|
||||
|
||||
/* avoid repetitive calls to ut_fold_binary() in the HASH_SEARCH
|
||||
macro */
|
||||
fold = ut_fold_binary(data, data_len);
|
||||
|
||||
#define IS_FOUND \
|
||||
node->data_len == data_len && memcmp(node->data, data, data_len) == 0
|
||||
|
||||
HASH_SEARCH(
|
||||
next, /* node->"next" */
|
||||
storage->hash, /* the hash table */
|
||||
fold, /* key */
|
||||
ha_storage_node_t*, /* type of node->next */
|
||||
node, /* auxiliary variable */
|
||||
, /* assertion */
|
||||
IS_FOUND); /* search criteria */
|
||||
|
||||
if (node == NULL) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
/* else */
|
||||
|
||||
return(node->data);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
Copies data into the storage and returns a pointer to the copy. If the
|
||||
same data chunk is already present, then pointer to it is returned.
|
||||
Data chunks are considered to be equal if len1 == len2 and
|
||||
memcmp(data1, data2, len1) == 0. If "data" is not present (and thus
|
||||
data_len bytes need to be allocated) and the size of storage is going to
|
||||
become more than "memlim" then "data" is not added and NULL is returned.
|
||||
To disable this behavior "memlim" can be set to 0, which stands for
|
||||
"no limit". */
|
||||
UNIV_INTERN
|
||||
const void*
|
||||
ha_storage_put_memlim(
|
||||
/*==================*/
|
||||
ha_storage_t* storage, /* in/out: hash storage */
|
||||
const void* data, /* in: data to store */
|
||||
ulint data_len, /* in: data length */
|
||||
ulint memlim) /* in: memory limit to obey */
|
||||
{
|
||||
void* raw;
|
||||
ha_storage_node_t* node;
|
||||
const void* data_copy;
|
||||
ulint fold;
|
||||
|
||||
/* check if data chunk is already present */
|
||||
data_copy = ha_storage_get(storage, data, data_len);
|
||||
if (data_copy != NULL) {
|
||||
|
||||
return(data_copy);
|
||||
}
|
||||
|
||||
/* not present */
|
||||
|
||||
/* check if we are allowed to allocate data_len bytes */
|
||||
if (memlim > 0
|
||||
&& ha_storage_get_size(storage) + data_len > memlim) {
|
||||
|
||||
return(NULL);
|
||||
}
|
||||
|
||||
/* we put the auxiliary node struct and the data itself in one
|
||||
continuous block */
|
||||
raw = mem_heap_alloc(storage->heap,
|
||||
sizeof(ha_storage_node_t) + data_len);
|
||||
|
||||
node = (ha_storage_node_t*) raw;
|
||||
data_copy = (byte*) raw + sizeof(*node);
|
||||
|
||||
memcpy((byte*) raw + sizeof(*node), data, data_len);
|
||||
|
||||
node->data_len = data_len;
|
||||
node->data = data_copy;
|
||||
|
||||
/* avoid repetitive calls to ut_fold_binary() in the HASH_INSERT
|
||||
macro */
|
||||
fold = ut_fold_binary(data, data_len);
|
||||
|
||||
HASH_INSERT(
|
||||
ha_storage_node_t, /* type used in the hash chain */
|
||||
next, /* node->"next" */
|
||||
storage->hash, /* the hash table */
|
||||
fold, /* key */
|
||||
node); /* add this data to the hash */
|
||||
|
||||
/* the output should not be changed because it will spoil the
|
||||
hash table */
|
||||
return(data_copy);
|
||||
}
|
||||
|
||||
#ifdef UNIV_COMPILE_TEST_FUNCS
|
||||
|
||||
void
|
||||
test_ha_storage()
|
||||
{
|
||||
ha_storage_t* storage;
|
||||
char buf[1024];
|
||||
int i;
|
||||
const void* stored[256];
|
||||
const void* p;
|
||||
|
||||
storage = ha_storage_create(0, 0);
|
||||
|
||||
for (i = 0; i < 256; i++) {
|
||||
|
||||
memset(buf, i, sizeof(buf));
|
||||
stored[i] = ha_storage_put(storage, buf, sizeof(buf));
|
||||
}
|
||||
|
||||
//ha_storage_empty(&storage);
|
||||
|
||||
for (i = 255; i >= 0; i--) {
|
||||
|
||||
memset(buf, i, sizeof(buf));
|
||||
p = ha_storage_put(storage, buf, sizeof(buf));
|
||||
|
||||
if (p != stored[i]) {
|
||||
|
||||
fprintf(stderr, "ha_storage_put() returned %p "
|
||||
"instead of %p, i=%d\n", p, stored[i], i);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fprintf(stderr, "all ok\n");
|
||||
|
||||
ha_storage_free(storage);
|
||||
}
|
||||
|
||||
#endif /* UNIV_COMPILE_TEST_FUNCS */
|
||||
165
storage/xtradb/ha/hash0hash.c
Normal file
165
storage/xtradb/ha/hash0hash.c
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/*****************************************************************************
|
||||
|
||||
Copyright (c) 1997, 2009, Innobase Oy. All Rights Reserved.
|
||||
|
||||
This program is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License as published by the Free Software
|
||||
Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
||||
FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License along with
|
||||
this program; if not, write to the Free Software Foundation, Inc., 59 Temple
|
||||
Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
|
||||
*****************************************************************************/
|
||||
|
||||
/******************************************************
|
||||
The simple hash table utility
|
||||
|
||||
Created 5/20/1997 Heikki Tuuri
|
||||
*******************************************************/
|
||||
|
||||
#include "hash0hash.h"
|
||||
#ifdef UNIV_NONINL
|
||||
#include "hash0hash.ic"
|
||||
#endif
|
||||
|
||||
#include "mem0mem.h"
|
||||
|
||||
/****************************************************************
|
||||
Reserves the mutex for a fold value in a hash table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
hash_mutex_enter(
|
||||
/*=============*/
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ulint fold) /* in: fold */
|
||||
{
|
||||
mutex_enter(hash_get_mutex(table, fold));
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Releases the mutex for a fold value in a hash table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
hash_mutex_exit(
|
||||
/*============*/
|
||||
hash_table_t* table, /* in: hash table */
|
||||
ulint fold) /* in: fold */
|
||||
{
|
||||
mutex_exit(hash_get_mutex(table, fold));
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Reserves all the mutexes of a hash table, in an ascending order. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
hash_mutex_enter_all(
|
||||
/*=================*/
|
||||
hash_table_t* table) /* in: hash table */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < table->n_mutexes; i++) {
|
||||
|
||||
mutex_enter(table->mutexes + i);
|
||||
}
|
||||
}
|
||||
|
||||
/****************************************************************
|
||||
Releases all the mutexes of a hash table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
hash_mutex_exit_all(
|
||||
/*================*/
|
||||
hash_table_t* table) /* in: hash table */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
for (i = 0; i < table->n_mutexes; i++) {
|
||||
|
||||
mutex_exit(table->mutexes + i);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Creates a hash table with >= n array cells. The actual number of cells is
|
||||
chosen to be a prime number slightly bigger than n. */
|
||||
UNIV_INTERN
|
||||
hash_table_t*
|
||||
hash_create(
|
||||
/*========*/
|
||||
/* out, own: created table */
|
||||
ulint n) /* in: number of array cells */
|
||||
{
|
||||
hash_cell_t* array;
|
||||
ulint prime;
|
||||
hash_table_t* table;
|
||||
|
||||
prime = ut_find_prime(n);
|
||||
|
||||
table = mem_alloc(sizeof(hash_table_t));
|
||||
|
||||
array = ut_malloc(sizeof(hash_cell_t) * prime);
|
||||
|
||||
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
|
||||
table->adaptive = FALSE;
|
||||
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
|
||||
table->array = array;
|
||||
table->n_cells = prime;
|
||||
table->n_mutexes = 0;
|
||||
table->mutexes = NULL;
|
||||
table->heaps = NULL;
|
||||
table->heap = NULL;
|
||||
table->magic_n = HASH_TABLE_MAGIC_N;
|
||||
|
||||
/* Initialize the cell array */
|
||||
hash_table_clear(table);
|
||||
|
||||
return(table);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Frees a hash table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
hash_table_free(
|
||||
/*============*/
|
||||
hash_table_t* table) /* in, own: hash table */
|
||||
{
|
||||
ut_a(table->mutexes == NULL);
|
||||
|
||||
ut_free(table->array);
|
||||
mem_free(table);
|
||||
}
|
||||
|
||||
/*****************************************************************
|
||||
Creates a mutex array to protect a hash table. */
|
||||
UNIV_INTERN
|
||||
void
|
||||
hash_create_mutexes_func(
|
||||
/*=====================*/
|
||||
hash_table_t* table, /* in: hash table */
|
||||
#ifdef UNIV_SYNC_DEBUG
|
||||
ulint sync_level, /* in: latching order level of the
|
||||
mutexes: used in the debug version */
|
||||
#endif /* UNIV_SYNC_DEBUG */
|
||||
ulint n_mutexes) /* in: number of mutexes, must be a
|
||||
power of 2 */
|
||||
{
|
||||
ulint i;
|
||||
|
||||
ut_a(n_mutexes > 0);
|
||||
ut_a(ut_is_2pow(n_mutexes));
|
||||
|
||||
table->mutexes = mem_alloc(n_mutexes * sizeof(mutex_t));
|
||||
|
||||
for (i = 0; i < n_mutexes; i++) {
|
||||
mutex_create(table->mutexes + i, sync_level);
|
||||
}
|
||||
|
||||
table->n_mutexes = n_mutexes;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue