summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/innodb-semi-consistent.result36
-rw-r--r--mysql-test/r/innodb.result76
-rw-r--r--mysql-test/r/innodb_autoinc_lock_mode_zero.result39
-rw-r--r--mysql-test/t/innodb-semi-consistent-master.opt1
-rw-r--r--mysql-test/t/innodb-semi-consistent.test46
-rw-r--r--mysql-test/t/innodb.test75
-rw-r--r--mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt1
-rw-r--r--mysql-test/t/innodb_autoinc_lock_mode_zero.test44
-rw-r--r--storage/innobase/buf/buf0lru.c2
-rw-r--r--storage/innobase/dict/dict0dict.c4
-rw-r--r--storage/innobase/dict/dict0load.c80
-rw-r--r--storage/innobase/handler/ha_innodb.cc98
-rw-r--r--storage/innobase/handler/ha_innodb.h14
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.c4
-rw-r--r--storage/innobase/include/db0err.h6
-rw-r--r--storage/innobase/include/ha_prototypes.h16
-rw-r--r--storage/innobase/include/mach0data.h11
-rw-r--r--storage/innobase/include/mach0data.ic37
-rw-r--r--storage/innobase/include/mem0dbg.h16
-rw-r--r--storage/innobase/include/mem0mem.ic16
-rw-r--r--storage/innobase/include/rem0rec.ic1
-rw-r--r--storage/innobase/include/row0mysql.h13
-rw-r--r--storage/innobase/include/sync0rw.h2
-rw-r--r--storage/innobase/include/univ.i28
-rw-r--r--storage/innobase/include/ut0ut.h18
-rw-r--r--storage/innobase/mem/mem0dbg.c40
-rw-r--r--storage/innobase/mem/mem0mem.c6
-rw-r--r--storage/innobase/row/row0mysql.c82
-rw-r--r--storage/innobase/row/row0sel.c69
-rw-r--r--storage/innobase/sync/sync0rw.c6
-rw-r--r--storage/innobase/ut/ut0ut.c71
31 files changed, 672 insertions, 286 deletions
diff --git a/mysql-test/r/innodb-semi-consistent.result b/mysql-test/r/innodb-semi-consistent.result
new file mode 100644
index 00000000000..ad7b70d0497
--- /dev/null
+++ b/mysql-test/r/innodb-semi-consistent.result
@@ -0,0 +1,36 @@
+set session transaction isolation level read committed;
+create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
+insert into t1 values (1),(2),(3),(4),(5),(6),(7);
+set autocommit=0;
+select * from t1 where a=3 lock in share mode;
+a
+3
+set session transaction isolation level read committed;
+set autocommit=0;
+update t1 set a=10 where a=5;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+commit;
+update t1 set a=10 where a=5;
+select * from t1 where a=2 for update;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+select * from t1 where a=2 limit 1 for update;
+a
+2
+update t1 set a=11 where a=6;
+update t1 set a=12 where a=2;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+update t1 set a=13 where a=1;
+ERROR HY000: Lock wait timeout exceeded; try restarting transaction
+commit;
+update t1 set a=14 where a=1;
+commit;
+select * from t1;
+a
+14
+2
+3
+4
+10
+11
+7
+drop table t1;
diff --git a/mysql-test/r/innodb.result b/mysql-test/r/innodb.result
index d0b67e90afb..9f6cde0292f 100644
--- a/mysql-test/r/innodb.result
+++ b/mysql-test/r/innodb.result
@@ -472,43 +472,6 @@ a b
3 3
drop table t1,t2;
CREATE TABLE t1 (
-id int(11) NOT NULL auto_increment,
-ggid varchar(32) binary DEFAULT '' NOT NULL,
-email varchar(64) DEFAULT '' NOT NULL,
-passwd varchar(32) binary DEFAULT '' NOT NULL,
-PRIMARY KEY (id),
-UNIQUE ggid (ggid)
-) ENGINE=innodb;
-insert into t1 (ggid,passwd) values ('test1','xxx');
-insert into t1 (ggid,passwd) values ('test2','yyy');
-insert into t1 (ggid,passwd) values ('test2','this will fail');
-ERROR 23000: Duplicate entry 'test2' for key 'ggid'
-insert into t1 (ggid,id) values ('this will fail',1);
-ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
-select * from t1 where ggid='test1';
-id ggid email passwd
-1 test1 xxx
-select * from t1 where passwd='xxx';
-id ggid email passwd
-1 test1 xxx
-select * from t1 where id=2;
-id ggid email passwd
-2 test2 yyy
-replace into t1 (ggid,id) values ('this will work',1);
-replace into t1 (ggid,passwd) values ('test2','this will work');
-update t1 set id=100,ggid='test2' where id=1;
-ERROR 23000: Duplicate entry 'test2' for key 'ggid'
-select * from t1;
-id ggid email passwd
-1 this will work
-4 test2 this will work
-select * from t1 where id=1;
-id ggid email passwd
-1 this will work
-select * from t1 where id=999;
-id ggid email passwd
-drop table t1;
-CREATE TABLE t1 (
user_name varchar(12),
password text,
subscribed char(1),
@@ -1751,13 +1714,13 @@ Variable_name Value
Innodb_page_size 16384
show status like "Innodb_rows_deleted";
Variable_name Value
-Innodb_rows_deleted 70
+Innodb_rows_deleted 69
show status like "Innodb_rows_inserted";
Variable_name Value
-Innodb_rows_inserted 1083
+Innodb_rows_inserted 1080
show status like "Innodb_rows_updated";
Variable_name Value
-Innodb_rows_updated 886
+Innodb_rows_updated 885
show status like "Innodb_row_lock_waits";
Variable_name Value
Innodb_row_lock_waits 0
@@ -3189,3 +3152,36 @@ c25 CHAR(255), c26 CHAR(255), c27 CHAR(255), c28 CHAR(255),
c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255)
) ENGINE = InnoDB;
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
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+DROP TABLE IF EXISTS t1, t2;
+Warnings:
+Note 1051 Unknown table 't1'
+Note 1051 Unknown table 't2'
+CREATE TABLE t1 ( a int ) ENGINE=InnoDB;
+CREATE TABLE t2 LIKE t1;
+SELECT * FROM t2;
+a
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+INSERT INTO t1 VALUES (1);
+COMMIT;
+SELECT * FROM t1 WHERE a=1;
+a
+1
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+SELECT * FROM t2;
+a
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+INSERT INTO t1 VALUES (2);
+COMMIT;
+SELECT * FROM t1 WHERE a=2;
+a
+2
+SELECT * FROM t1 WHERE a=2;
+a
+2
+DROP TABLE t1;
+DROP TABLE t2;
diff --git a/mysql-test/r/innodb_autoinc_lock_mode_zero.result b/mysql-test/r/innodb_autoinc_lock_mode_zero.result
new file mode 100644
index 00000000000..3d016684338
--- /dev/null
+++ b/mysql-test/r/innodb_autoinc_lock_mode_zero.result
@@ -0,0 +1,39 @@
+drop table if exists t1;
+CREATE TABLE t1 (
+id int(11) NOT NULL auto_increment,
+ggid varchar(32) binary DEFAULT '' NOT NULL,
+email varchar(64) DEFAULT '' NOT NULL,
+passwd varchar(32) binary DEFAULT '' NOT NULL,
+PRIMARY KEY (id),
+UNIQUE ggid (ggid)
+) ENGINE=innodb;
+insert into t1 (ggid,passwd) values ('test1','xxx');
+insert into t1 (ggid,passwd) values ('test2','yyy');
+insert into t1 (ggid,passwd) values ('test2','this will fail');
+ERROR 23000: Duplicate entry 'test2' for key 'ggid'
+insert into t1 (ggid,id) values ('this will fail',1);
+ERROR 23000: Duplicate entry '1' for key 'PRIMARY'
+select * from t1 where ggid='test1';
+id ggid email passwd
+1 test1 xxx
+select * from t1 where passwd='xxx';
+id ggid email passwd
+1 test1 xxx
+select * from t1 where id=2;
+id ggid email passwd
+2 test2 yyy
+replace into t1 (ggid,id) values ('this will work',1);
+replace into t1 (ggid,passwd) values ('test2','this will work');
+update t1 set id=100,ggid='test2' where id=1;
+ERROR 23000: Duplicate entry 'test2' for key 'ggid'
+select * from t1;
+id ggid email passwd
+1 this will work
+3 test2 this will work
+select * from t1 where id=1;
+id ggid email passwd
+1 this will work
+select * from t1 where id=999;
+id ggid email passwd
+drop table t1;
+End of tests
diff --git a/mysql-test/t/innodb-semi-consistent-master.opt b/mysql-test/t/innodb-semi-consistent-master.opt
new file mode 100644
index 00000000000..2746e4e184e
--- /dev/null
+++ b/mysql-test/t/innodb-semi-consistent-master.opt
@@ -0,0 +1 @@
+--innodb_locks_unsafe_for_binlog=true --innodb_lock_wait_timeout=2
diff --git a/mysql-test/t/innodb-semi-consistent.test b/mysql-test/t/innodb-semi-consistent.test
new file mode 100644
index 00000000000..7a9231b508f
--- /dev/null
+++ b/mysql-test/t/innodb-semi-consistent.test
@@ -0,0 +1,46 @@
+-- source include/not_embedded.inc
+-- source include/have_innodb.inc
+
+# basic tests of semi-consistent reads
+
+connect (a,localhost,root,,);
+connect (b,localhost,root,,);
+connection a;
+set session transaction isolation level read committed;
+create table t1(a int not null) engine=innodb DEFAULT CHARSET=latin1;
+insert into t1 values (1),(2),(3),(4),(5),(6),(7);
+set autocommit=0;
+# this should lock the entire table
+select * from t1 where a=3 lock in share mode;
+connection b;
+set session transaction isolation level read committed;
+set autocommit=0;
+-- error ER_LOCK_WAIT_TIMEOUT
+update t1 set a=10 where a=5;
+connection a;
+commit;
+connection b;
+update t1 set a=10 where a=5;
+connection a;
+-- error ER_LOCK_WAIT_TIMEOUT
+select * from t1 where a=2 for update;
+# this should lock the records (1),(2)
+select * from t1 where a=2 limit 1 for update;
+connection b;
+update t1 set a=11 where a=6;
+-- error ER_LOCK_WAIT_TIMEOUT
+update t1 set a=12 where a=2;
+-- error ER_LOCK_WAIT_TIMEOUT
+update t1 set a=13 where a=1;
+connection a;
+commit;
+connection b;
+update t1 set a=14 where a=1;
+commit;
+connection a;
+select * from t1;
+drop table t1;
+
+connection default;
+disconnect a;
+disconnect b;
diff --git a/mysql-test/t/innodb.test b/mysql-test/t/innodb.test
index cc1ef6f9730..77c450035c7 100644
--- a/mysql-test/t/innodb.test
+++ b/mysql-test/t/innodb.test
@@ -327,39 +327,6 @@ select * from t2;
drop table t1,t2;
#
-# Search on unique key
-#
-
-CREATE TABLE t1 (
- id int(11) NOT NULL auto_increment,
- ggid varchar(32) binary DEFAULT '' NOT NULL,
- email varchar(64) DEFAULT '' NOT NULL,
- passwd varchar(32) binary DEFAULT '' NOT NULL,
- PRIMARY KEY (id),
- UNIQUE ggid (ggid)
-) ENGINE=innodb;
-
-insert into t1 (ggid,passwd) values ('test1','xxx');
-insert into t1 (ggid,passwd) values ('test2','yyy');
--- error ER_DUP_ENTRY
-insert into t1 (ggid,passwd) values ('test2','this will fail');
--- error ER_DUP_ENTRY
-insert into t1 (ggid,id) values ('this will fail',1);
-
-select * from t1 where ggid='test1';
-select * from t1 where passwd='xxx';
-select * from t1 where id=2;
-
-replace into t1 (ggid,id) values ('this will work',1);
-replace into t1 (ggid,passwd) values ('test2','this will work');
--- error ER_DUP_ENTRY
-update t1 set id=100,ggid='test2' where id=1;
-select * from t1;
-select * from t1 where id=1;
-select * from t1 where id=999;
-drop table t1;
-
-#
# ORDER BY on not primary key
#
@@ -2323,6 +2290,48 @@ CREATE TABLE t1 (
c29 CHAR(255), c30 CHAR(255), c31 CHAR(255), c32 CHAR(255)
) ENGINE = InnoDB;
+#
+# Bug #21409 Incorrect result returned when in READ-COMMITTED with
+# query_cache ON
+#
+CONNECT (c1,localhost,root,,);
+CONNECT (c2,localhost,root,,);
+CONNECTION c1;
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+DROP TABLE IF EXISTS t1, t2;
+CREATE TABLE t1 ( a int ) ENGINE=InnoDB;
+CREATE TABLE t2 LIKE t1;
+SELECT * FROM t2;
+CONNECTION c2;
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+INSERT INTO t1 VALUES (1);
+COMMIT;
+CONNECTION c1;
+SELECT * FROM t1 WHERE a=1;
+DISCONNECT c1;
+DISCONNECT c2;
+CONNECT (c1,localhost,root,,);
+CONNECT (c2,localhost,root,,);
+CONNECTION c1;
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+SELECT * FROM t2;
+CONNECTION c2;
+SET TX_ISOLATION='read-committed';
+SET AUTOCOMMIT=0;
+INSERT INTO t1 VALUES (2);
+COMMIT;
+CONNECTION c1;
+# The result set below should be the same for both selects
+SELECT * FROM t1 WHERE a=2;
+SELECT * FROM t1 WHERE a=2;
+DROP TABLE t1;
+DROP TABLE t2;
+DISCONNECT c1;
+DISCONNECT c2;
+
#######################################################################
# #
# Please, DO NOT TOUCH this file as well as the innodb.result file. #
diff --git a/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt b/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt
new file mode 100644
index 00000000000..fad0da2ac2e
--- /dev/null
+++ b/mysql-test/t/innodb_autoinc_lock_mode_zero-master.opt
@@ -0,0 +1 @@
+--innodb-autoinc-lock-mode=0
diff --git a/mysql-test/t/innodb_autoinc_lock_mode_zero.test b/mysql-test/t/innodb_autoinc_lock_mode_zero.test
new file mode 100644
index 00000000000..96f748673c0
--- /dev/null
+++ b/mysql-test/t/innodb_autoinc_lock_mode_zero.test
@@ -0,0 +1,44 @@
+# This test runs with old-style locking, as:
+# --innodb-autoinc-lock-mode=0
+
+-- source include/have_innodb.inc
+
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+
+#
+# Search on unique key
+#
+
+CREATE TABLE t1 (
+ id int(11) NOT NULL auto_increment,
+ ggid varchar(32) binary DEFAULT '' NOT NULL,
+ email varchar(64) DEFAULT '' NOT NULL,
+ passwd varchar(32) binary DEFAULT '' NOT NULL,
+ PRIMARY KEY (id),
+ UNIQUE ggid (ggid)
+) ENGINE=innodb;
+
+insert into t1 (ggid,passwd) values ('test1','xxx');
+insert into t1 (ggid,passwd) values ('test2','yyy');
+-- error ER_DUP_ENTRY
+insert into t1 (ggid,passwd) values ('test2','this will fail');
+-- error ER_DUP_ENTRY
+insert into t1 (ggid,id) values ('this will fail',1);
+
+select * from t1 where ggid='test1';
+select * from t1 where passwd='xxx';
+select * from t1 where id=2;
+
+replace into t1 (ggid,id) values ('this will work',1);
+replace into t1 (ggid,passwd) values ('test2','this will work');
+-- error ER_DUP_ENTRY
+update t1 set id=100,ggid='test2' where id=1;
+select * from t1;
+select * from t1 where id=1;
+select * from t1 where id=999;
+drop table t1;
+
+--echo End of tests
diff --git a/storage/innobase/buf/buf0lru.c b/storage/innobase/buf/buf0lru.c
index 7b49a7641af..f3913ed49b7 100644
--- a/storage/innobase/buf/buf0lru.c
+++ b/storage/innobase/buf/buf0lru.c
@@ -881,7 +881,7 @@ buf_LRU_block_free_non_file_page(
UT_LIST_ADD_FIRST(free, buf_pool->free, block);
block->in_free_list = TRUE;
- UNIV_MEM_FREE(block->frame, UNIV_PAGE_SIZE);
+ UNIV_MEM_ASSERT_AND_FREE(block->frame, UNIV_PAGE_SIZE);
if (srv_use_awe && block->frame) {
/* Add to the list of mapped pages */
diff --git a/storage/innobase/dict/dict0dict.c b/storage/innobase/dict/dict0dict.c
index 595dfb06ee5..368ff3c2bc2 100644
--- a/storage/innobase/dict/dict0dict.c
+++ b/storage/innobase/dict/dict0dict.c
@@ -441,6 +441,8 @@ dict_table_autoinc_initialize(
dict_table_t* table, /* in: table */
ib_longlong value) /* in: next value to assign to a row */
{
+ ut_ad(mutex_own(&table->autoinc_mutex));
+
table->autoinc_inited = TRUE;
table->autoinc = value;
}
@@ -457,6 +459,8 @@ dict_table_autoinc_read(
{
ib_longlong value;
+ ut_ad(mutex_own(&table->autoinc_mutex));
+
if (!table->autoinc_inited) {
value = 0;
diff --git a/storage/innobase/dict/dict0load.c b/storage/innobase/dict/dict0load.c
index 1ff1fd54cec..f594e64f517 100644
--- a/storage/innobase/dict/dict0load.c
+++ b/storage/innobase/dict/dict0load.c
@@ -551,11 +551,13 @@ dict_load_fields(
Loads definitions for table indexes. Adds them to the data dictionary
cache. */
static
-ibool
+ulint
dict_load_indexes(
/*==============*/
- /* out: TRUE if ok, FALSE if corruption
- of dictionary table */
+ /* out: DB_SUCCESS if ok, DB_CORRUPTION
+ if corruption of dictionary table or
+ DB_UNSUPPORTED if table has unknown index
+ type */
dict_table_t* table, /* in: table */
mem_heap_t* heap) /* in: memory heap for temporary storage */
{
@@ -578,6 +580,7 @@ dict_load_indexes(
ibool is_sys_table;
dulint id;
mtr_t mtr;
+ ulint error = DB_SUCCESS;
ut_ad(mutex_own(&(dict_sys->mutex)));
@@ -624,10 +627,8 @@ dict_load_indexes(
dict_load_report_deleted_index(table->name,
ULINT_UNDEFINED);
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
-
- return(FALSE);
+ error = DB_CORRUPTION;
+ goto func_exit;
}
field = rec_get_nth_field_old(rec, 1, &len);
@@ -653,7 +654,18 @@ dict_load_indexes(
field = rec_get_nth_field_old(rec, 8, &len);
page_no = mach_read_from_4(field);
- if (page_no == FIL_NULL) {
+ /* We check for unsupported types first, so that the
+ subsequent checks are relevant for the supported types. */
+ if (type & ~(DICT_CLUSTERED | DICT_UNIQUE)) {
+
+ fprintf(stderr,
+ "InnoDB: Error: unknown type %lu"
+ " of index %s of table %s\n",
+ (ulong) type, name_buf, table->name);
+
+ error = DB_UNSUPPORTED;
+ goto func_exit;
+ } else if (page_no == FIL_NULL) {
fprintf(stderr,
"InnoDB: Error: trying to load index %s"
@@ -661,14 +673,10 @@ dict_load_indexes(
"InnoDB: but the index tree has been freed!\n",
name_buf, table->name);
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
-
- return(FALSE);
- }
-
- if ((type & DICT_CLUSTERED) == 0
- && NULL == dict_table_get_first_index(table)) {
+ error = DB_CORRUPTION;
+ goto func_exit;
+ } else if ((type & DICT_CLUSTERED) == 0
+ && NULL == dict_table_get_first_index(table)) {
fprintf(stderr,
"InnoDB: Error: trying to load index %s"
@@ -677,18 +685,14 @@ dict_load_indexes(
" is not clustered!\n",
name_buf, table->name);
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
-
- return(FALSE);
- }
-
- if (is_sys_table
- && ((type & DICT_CLUSTERED)
- || ((table == dict_sys->sys_tables)
- && (name_len == (sizeof "ID_IND") - 1)
- && (0 == ut_memcmp(name_buf, "ID_IND",
- name_len))))) {
+ error = DB_CORRUPTION;
+ goto func_exit;
+ } else if (is_sys_table
+ && ((type & DICT_CLUSTERED)
+ || ((table == dict_sys->sys_tables)
+ && (name_len == (sizeof "ID_IND") - 1)
+ && (0 == ut_memcmp(name_buf,
+ "ID_IND", name_len))))) {
/* The index was created in memory already at booting
of the database server */
@@ -704,10 +708,11 @@ dict_load_indexes(
btr_pcur_move_to_next_user_rec(&pcur, &mtr);
}
+func_exit:
btr_pcur_close(&pcur);
mtr_commit(&mtr);
- return(TRUE);
+ return(error);
}
/************************************************************************
@@ -857,11 +862,20 @@ err_exit:
mem_heap_empty(heap);
- dict_load_indexes(table, heap);
-
- err = dict_load_foreigns(table->name, TRUE);
+ err = dict_load_indexes(table, heap);
+
+ /* If the force recovery flag is set, we open the table irrespective
+ of the error condition, since the user may want to dump data from the
+ clustered index. However we load the foreign key information only if
+ all indexes were loaded. */
+ if (err != DB_SUCCESS && !srv_force_recovery) {
+ dict_mem_table_free(table);
+ table = NULL;
+ } else if (err == DB_SUCCESS) {
+ err = dict_load_foreigns(table->name, TRUE);
+ }
#if 0
- if (err != DB_SUCCESS) {
+ if (err != DB_SUCCESS && table != NULL) {
mutex_enter(&dict_foreign_err_mutex);
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index 783553f5d87..61f16522cff 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -129,6 +129,7 @@ static my_bool innobase_locks_unsafe_for_binlog = FALSE;
static my_bool innobase_rollback_on_timeout = FALSE;
static my_bool innobase_create_status_file = FALSE;
static my_bool innobase_stats_on_metadata = TRUE;
+static my_bool innobase_use_adaptive_hash_indexes = TRUE;
static char* internal_innobase_data_file_path = NULL;
@@ -1246,8 +1247,7 @@ innobase_invalidate_query_cache(
}
/*********************************************************************
-Display an SQL identifier.
-This definition must match the one in innobase/ut/ut0ut.c! */
+Display an SQL identifier. */
extern "C"
void
innobase_print_identifier(
@@ -1635,6 +1635,9 @@ innobase_init(
srv_stats_on_metadata = (ibool) innobase_stats_on_metadata;
+ srv_use_adaptive_hash_indexes =
+ (ibool) innobase_use_adaptive_hash_indexes;
+
srv_print_verbose_log = mysqld_embedded ? 0 : 1;
/* Store the default charset-collation number of this MySQL
@@ -2320,13 +2323,18 @@ ha_innobase::open(
if (NULL == ib_table) {
ut_print_timestamp(stderr);
- sql_print_error("Cannot find table %s from the internal data "
- "dictionary\nof InnoDB though the .frm file "
- "for the table exists. Maybe you\nhave "
- "deleted and recreated InnoDB data files but "
- "have forgotten\nto delete the corresponding "
- ".frm files of InnoDB tables, or you\n"
- "have moved .frm files to another database?\n"
+ sql_print_error("Cannot find or open table %s from\n"
+ "the internal data dictionary of InnoDB "
+ "though the .frm file for the\n"
+ "table exists. Maybe you have deleted and "
+ "recreated InnoDB data\n"
+ "files but have forgotten to delete the "
+ "corresponding .frm files\n"
+ "of InnoDB tables, or you have moved .frm "
+ "files to another database?\n"
+ "or, the table contains indexes that this "
+ "version of the engine\n"
+ "doesn't support.\n"
"See http://dev.mysql.com/doc/refman/5.1/en/innodb-troubleshooting.html\n"
"how you can resolve the problem.\n",
norm_name);
@@ -3476,6 +3484,7 @@ no_commit:
/* Handle duplicate key errors */
if (auto_inc_used) {
+ ulint err;
ulonglong auto_inc;
/* Note the number of rows processed for this statement, used
@@ -3529,7 +3538,11 @@ set_max_autoinc:
ut_a(prebuilt->table->autoinc_increment > 0);
auto_inc += prebuilt->table->autoinc_increment;
- innobase_set_max_autoinc(auto_inc);
+ err = innobase_set_max_autoinc(auto_inc);
+
+ if (err != DB_SUCCESS) {
+ error = err;
+ }
}
break;
}
@@ -3765,7 +3778,7 @@ ha_innobase::update_row(
if (auto_inc != 0) {
auto_inc += prebuilt->table->autoinc_increment;
- innobase_set_max_autoinc(auto_inc);
+ error = innobase_set_max_autoinc(auto_inc);
}
}
@@ -6304,6 +6317,9 @@ ha_innobase::start_stmt(
innobase_release_stat_resources(trx);
+ /* Reset the AUTOINC statement level counter for multi-row INSERTs. */
+ trx->n_autoinc_rows = 0;
+
prebuilt->sql_stat_start = TRUE;
prebuilt->hint_need_to_fetch_extra_cols = 0;
reset_template(prebuilt);
@@ -6446,9 +6462,6 @@ ha_innobase::external_lock(
innobase_register_stmt(ht, thd);
}
- trx->n_mysql_tables_in_use++;
- prebuilt->mysql_has_locked = TRUE;
-
if (trx->isolation_level == TRX_ISO_SERIALIZABLE
&& prebuilt->select_lock_type == LOCK_NONE
&& thd_test_options(thd,
@@ -6497,6 +6510,9 @@ ha_innobase::external_lock(
trx->mysql_n_tables_locked++;
}
+ trx->n_mysql_tables_in_use++;
+ prebuilt->mysql_has_locked = TRUE;
+
DBUG_RETURN(0);
}
@@ -7120,8 +7136,8 @@ the value of the auto-inc counter. */
int
ha_innobase::innobase_read_and_init_auto_inc(
/*=========================================*/
- /* out: 0 or error code:
- deadlock or lock wait timeout */
+ /* out: 0 or generic MySQL
+ error code */
longlong* value) /* out: the autoinc value */
{
longlong auto_inc;
@@ -7178,9 +7194,9 @@ ha_innobase::innobase_read_and_init_auto_inc(
++auto_inc;
dict_table_autoinc_initialize(innodb_table, auto_inc);
} else {
- fprintf(stderr, " InnoDB error: Couldn't read the "
- "max AUTOINC value from index (%s).\n",
- index->name);
+ fprintf(stderr, " InnoDB error (%lu): Couldn't read "
+ "the max AUTOINC value from the index (%s).\n",
+ error, index->name);
mysql_error = 1;
}
@@ -7217,6 +7233,11 @@ ha_innobase::innobase_get_auto_increment(
{
ulong error;
+ *value = 0;
+
+ /* Note: If the table is not initialized when we attempt the
+ read below. We initialize the table's auto-inc counter and
+ always do a reread of the AUTOINC value. */
do {
error = innobase_autoinc_lock();
@@ -7256,7 +7277,16 @@ ha_innobase::innobase_get_auto_increment(
} else {
*value = (ulonglong) autoinc;
}
+ /* A deadlock error during normal processing is OK
+ and can be ignored. */
+ } else if (error != DB_DEADLOCK) {
+
+ ut_print_timestamp(stderr);
+ sql_print_error(" InnoDB Error %lu in "
+ "::innobase_get_auto_increment()",
+ error);
}
+
} while (*value == 0 && error == DB_SUCCESS);
return(error);
@@ -7272,7 +7302,7 @@ we have a table-level lock). offset, increment, nb_desired_values are ignored.
void
ha_innobase::get_auto_increment(
-/*=================================*/
+/*============================*/
ulonglong offset, /* in: */
ulonglong increment, /* in: table autoinc increment */
ulonglong nb_desired_values, /* in: number of values reqd */
@@ -7289,13 +7319,6 @@ ha_innobase::get_auto_increment(
error = innobase_get_auto_increment(&autoinc);
if (error != DB_SUCCESS) {
- /* This should never happen in the code > ver 5.0.6,
- since we call this function only after the counter
- has been initialized. */
-
- ut_print_timestamp(stderr);
- sql_print_error("Error %lu in ::get_auto_increment()", error);
-
*first_value = (~(ulonglong) 0);
return;
}
@@ -7310,6 +7333,11 @@ ha_innobase::get_auto_increment(
trx = prebuilt->trx;
+ /* Note: We can't rely on *first_value since some MySQL engines,
+ in particular the partition engine, don't initialize it to 0 when
+ invoking this method. So we are not sure if it's guaranteed to
+ be 0 or not. */
+
/* Called for the first time ? */
if (trx->n_autoinc_rows == 0) {
@@ -7318,16 +7346,16 @@ ha_innobase::get_auto_increment(
/* It's possible for nb_desired_values to be 0:
e.g., INSERT INTO T1(C) SELECT C FROM T2; */
if (nb_desired_values == 0) {
-
+
trx->n_autoinc_rows = 1;
}
-
+
set_if_bigger(*first_value, autoinc);
/* Not in the middle of a mult-row INSERT. */
} else if (prebuilt->last_value == 0) {
set_if_bigger(*first_value, autoinc);
}
-
+
*nb_reserved_values = trx->n_autoinc_rows;
/* With old style AUTOINC locking we only update the table's
@@ -7359,7 +7387,9 @@ ha_innobase::get_auto_increment(
/* See comment in handler.h */
int
-ha_innobase::reset_auto_increment(ulonglong value)
+ha_innobase::reset_auto_increment(
+/*==============================*/
+ ulonglong value) /* in: new value for table autoinc */
{
DBUG_ENTER("ha_innobase::reset_auto_increment");
@@ -7923,6 +7953,11 @@ static MYSQL_SYSVAR_BOOL(stats_on_metadata, innobase_stats_on_metadata,
"Enable statistics gathering for metadata commands such as SHOW TABLE STATUS (on by default)",
NULL, NULL, TRUE);
+static MYSQL_SYSVAR_BOOL(use_adaptive_hash_indexes, innobase_use_adaptive_hash_indexes,
+ PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
+ "Enable the InnoDB adaptive hash indexes (enabled by default)",
+ NULL, NULL, TRUE);
+
static MYSQL_SYSVAR_LONG(additional_mem_pool_size, innobase_additional_mem_pool_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Size of a memory pool InnoDB uses to store data dictionary information and other internal data structures.",
@@ -8051,6 +8086,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(open_files),
MYSQL_SYSVAR(rollback_on_timeout),
MYSQL_SYSVAR(stats_on_metadata),
+ MYSQL_SYSVAR(use_adaptive_hash_indexes),
MYSQL_SYSVAR(status_file),
MYSQL_SYSVAR(support_xa),
MYSQL_SYSVAR(sync_spin_loops),
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index fe5ebd57990..773884b6584 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -250,17 +250,3 @@ int thd_binlog_format(const MYSQL_THD thd);
*/
void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
}
-
-/*
- don't delete it - it may be re-enabled later
- as an optimization for the most common case InnoDB+binlog
-*/
-#if 0
-int innobase_report_binlog_offset_and_commit(
- THD* thd,
- void* trx_handle,
- char* log_file_name,
- my_off_t end_offset);
-int innobase_commit_complete(void* trx_handle);
-void innobase_store_binlog_offset_and_flush_log(char *binlog_name,longlong offset);
-#endif
diff --git a/storage/innobase/ibuf/ibuf0ibuf.c b/storage/innobase/ibuf/ibuf0ibuf.c
index 44972356304..126fd9fdd33 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.c
+++ b/storage/innobase/ibuf/ibuf0ibuf.c
@@ -2900,7 +2900,7 @@ dump:
ut_print_timestamp(stderr);
fprintf(stderr,
- "InnoDB: Error: Insert buffer insert"
+ " InnoDB: Error: Insert buffer insert"
" fails; page free %lu,"
" dtuple size %lu\n",
(ulong) page_get_max_insert_size(
@@ -2925,7 +2925,7 @@ dump:
buf_frame_get_page_no(page),
IBUF_BITMAP_FREE, mtr);
- fprintf(stderr, "Bitmap bits %lu\n",
+ fprintf(stderr, "InnoDB: Bitmap bits %lu\n",
(ulong) old_bits);
fputs("InnoDB: Submit a detailed bug report"
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index 0aa1b87e470..ed7ce151718 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -61,12 +61,14 @@ Created 5/24/1996 Heikki Tuuri
activated by the operation would
lead to a duplicate key in some
table */
-
#define DB_TOO_MANY_CONCURRENT_TRXS 47 /* when InnoDB runs out of the
preconfigured undo slots, this can
only happen when there are too many
concurrent transactions */
-
+#define DB_UNSUPPORTED 48 /* when InnoDB sees any artefact or
+ a feature that it can't recoginize or
+ work with e.g., FT indexes created by
+ a later version of the engine. */
/* The following are partial failure codes */
#define DB_FAIL 1000
#define DB_OVERFLOW 1001
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index 7fb50988941..ef0722321af 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -1,6 +1,8 @@
#ifndef HA_INNODB_PROTOTYPES_H
#define HA_INNODB_PROTOTYPES_H
+#ifndef UNIV_HOTBACKUP
+
#include "univ.i" /* ulint, uint */
#include "m_ctype.h" /* CHARSET_INFO */
@@ -22,6 +24,19 @@ innobase_convert_string(
CHARSET_INFO* from_cs,
uint* errors);
+/*********************************************************************
+Display an SQL identifier. */
+
+void
+innobase_print_identifier(
+/*======================*/
+ FILE* f, /* in: output stream */
+ trx_t* trx, /* in: transaction */
+ ibool table_id,/* in: TRUE=print a table name,
+ FALSE=print other identifier */
+ const char* name, /* in: name to print */
+ ulint namelen);/* in: length of name */
+
/**********************************************************************
Returns true if the thread is the replication thread on the slave
server. Used in srv_conc_enter_innodb() to determine if the thread
@@ -49,3 +64,4 @@ thd_has_edited_nontrans_tables(
void* thd); /* in: thread handle (THD*) */
#endif
+#endif
diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h
index 8377114a723..37d862cc678 100644
--- a/storage/innobase/include/mach0data.h
+++ b/storage/innobase/include/mach0data.h
@@ -327,6 +327,17 @@ mach_write_to_2_little_endian(
byte* dest, /* in: where to write */
ulint n); /* in: unsigned long int to write */
+/*************************************************************
+Convert integral type from storage byte order (big endian) to
+host byte order. */
+UNIV_INLINE
+void
+mach_read_int_type(
+/*===============*/
+ byte* dest, /* out: where to write */
+ const byte* src, /* in: where to read from */
+ ulint len, /* in: length of src */
+ ibool unsigned_type); /* in: signed or unsigned flag */
#ifndef UNIV_NONINL
#include "mach0data.ic"
#endif
diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic
index 03ece7529a8..64fb87f56ed 100644
--- a/storage/innobase/include/mach0data.ic
+++ b/storage/innobase/include/mach0data.ic
@@ -7,6 +7,8 @@ to the machine format.
Created 11/28/1995 Heikki Tuuri
***********************************************************************/
+#include "ut0mem.h"
+
/***********************************************************
The following function is used to store data in one byte. */
UNIV_INLINE
@@ -689,3 +691,38 @@ mach_write_to_2_little_endian(
*dest = (byte)(n & 0xFFUL);
}
+
+/*************************************************************
+Convert integral type from storage byte order (big endian) to
+host byte order. */
+UNIV_INLINE
+void
+mach_read_int_type(
+/*===============*/
+ byte* dest, /* out: where to write */
+ const byte* src, /* in: where to read from */
+ ulint len, /* in: length of src */
+ ibool unsigned_type) /* in: signed or unsigned flag */
+{
+#ifdef WORDS_BIGENDIAN
+ memcpy(dest, src, len);
+
+ if (!unsigned_type) {
+ dest[0] ^= 128;
+ }
+#else
+ byte* ptr;
+
+ /* Convert integer data from Innobase to a little-endian format,
+ sign bit restored to normal. */
+
+ for (ptr = dest + len; ptr != dest; ++src) {
+ --ptr;
+ *ptr = *src;
+ }
+
+ if (!unsigned_type) {
+ dest[len - 1] ^= 128;
+ }
+#endif
+}
diff --git a/storage/innobase/include/mem0dbg.h b/storage/innobase/include/mem0dbg.h
index 36cd7a89565..2393e4edb54 100644
--- a/storage/innobase/include/mem0dbg.h
+++ b/storage/innobase/include/mem0dbg.h
@@ -60,6 +60,14 @@ mem_heap_validate_or_print(
ulint* n_blocks); /* out: number of blocks in the heap,
if a NULL pointer is passed as this
argument, it is ignored */
+/******************************************************************
+Validates the contents of a memory heap. */
+
+ibool
+mem_heap_validate(
+/*==============*/
+ /* out: TRUE if ok */
+ mem_heap_t* heap); /* in: memory heap */
#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
#ifdef UNIV_DEBUG
/******************************************************************
@@ -71,14 +79,6 @@ mem_heap_check(
/* out: TRUE if ok */
mem_heap_t* heap); /* in: memory heap */
#endif /* UNIV_DEBUG */
-/******************************************************************
-Validates the contents of a memory heap. */
-
-ibool
-mem_heap_validate(
-/*==============*/
- /* out: TRUE if ok */
- mem_heap_t* heap); /* in: memory heap */
#ifdef UNIV_MEM_DEBUG
/*********************************************************************
TRUE if no memory is currently allocated. */
diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic
index adae9ad8a33..6227a27f277 100644
--- a/storage/innobase/include/mem0mem.ic
+++ b/storage/innobase/include/mem0mem.ic
@@ -271,19 +271,16 @@ mem_heap_free_heap_top(
ut_ad(mem_block_get_start(block) <= mem_block_get_free(block));
/* In the debug version erase block from top up */
- {
- ulint len = (byte*)block + block->len - old_top;
- mem_erase_buf(old_top, len);
- UNIV_MEM_FREE(old_top, len);
- }
+ mem_erase_buf(old_top, (byte*)block + block->len - old_top);
/* Update allocated memory count */
mutex_enter(&mem_hash_mutex);
mem_current_allocated_memory -= (total_size - size);
mutex_exit(&mem_hash_mutex);
#else /* UNIV_MEM_DEBUG */
- UNIV_MEM_FREE(old_top, (byte*)block + block->len - old_top);
+ UNIV_MEM_ASSERT_W(old_top, (byte*)block + block->len - old_top);
#endif /* UNIV_MEM_DEBUG */
+ UNIV_MEM_ALLOC(old_top, (byte*)block + block->len - old_top);
/* If free == start, we may free the block if it is not the first
one */
@@ -363,6 +360,7 @@ mem_heap_free_top(
/* Subtract the free field of block */
mem_block_set_free(block, mem_block_get_free(block)
- MEM_SPACE_NEEDED(n));
+ UNIV_MEM_ASSERT_W((byte*) block + mem_block_get_free(block), n);
#ifdef UNIV_MEM_DEBUG
ut_ad(mem_block_get_start(block) <= mem_block_get_free(block));
@@ -378,7 +376,11 @@ mem_heap_free_top(
== mem_block_get_start(block))) {
mem_heap_block_free(heap, block);
} else {
- UNIV_MEM_FREE((byte*) block + mem_block_get_free(block), n);
+ /* Avoid a bogus UNIV_MEM_ASSERT_W() warning in a
+ subsequent invocation of mem_heap_free_top().
+ Originally, this was UNIV_MEM_FREE(), to catch writes
+ to freed memory. */
+ UNIV_MEM_ALLOC((byte*) block + mem_block_get_free(block), n);
}
}
diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic
index 95aa65fabba..5a4a0a0b5df 100644
--- a/storage/innobase/include/rem0rec.ic
+++ b/storage/innobase/include/rem0rec.ic
@@ -801,6 +801,7 @@ rec_offs_set_n_alloc(
{
ut_ad(offsets);
ut_ad(n_alloc > 0);
+ UNIV_MEM_ASSERT_AND_ALLOC(offsets, n_alloc * sizeof *offsets);
offsets[0] = n_alloc;
}
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index aabb7f5f047..fd7ec8918ee 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -319,9 +319,11 @@ row_mysql_unfreeze_data_dictionary(
/*===============================*/
trx_t* trx); /* in: transaction */
/*************************************************************************
-Does a table creation operation for MySQL. If the name of the created
-table ends to characters INNODB_MONITOR, then this also starts
-printing of monitor output by the master thread. */
+Drops a table for MySQL. If the name of the table ends in
+one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
+"innodb_table_monitor", then this will also start the printing of monitor
+output by the master thread. If the table name ends in "innodb_mem_validate",
+InnoDB will try to invoke mem_validate(). */
int
row_create_table_for_mysql(
@@ -399,8 +401,9 @@ row_truncate_table_for_mysql(
dict_table_t* table, /* in: table handle */
trx_t* trx); /* in: transaction handle */
/*************************************************************************
-Drops a table for MySQL. If the name of the dropped table ends to
-characters INNODB_MONITOR, then this also stops printing of monitor
+Drops a table for MySQL. If the name of the dropped table ends in
+one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
+"innodb_table_monitor", then this will also stop the printing of monitor
output by the master thread. */
int
diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h
index abf04253141..7d2f63803d0 100644
--- a/storage/innobase/include/sync0rw.h
+++ b/storage/innobase/include/sync0rw.h
@@ -101,6 +101,7 @@ void
rw_lock_free(
/*=========*/
rw_lock_t* lock); /* in: rw-lock */
+#ifdef UNIV_DEBUG
/**********************************************************************
Checks that the rw-lock has been initialized and that there are no
simultaneous shared and exclusive locks. */
@@ -109,6 +110,7 @@ ibool
rw_lock_validate(
/*=============*/
rw_lock_t* lock);
+#endif /* UNIV_DEBUG */
/******************************************************************
NOTE! The following macros should be used in rw s-locking, not the
corresponding function. */
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index ba8e6e56219..d845c1006ee 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -308,11 +308,39 @@ typedef void* os_thread_ret_t;
# define UNIV_MEM_INVALID(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
# define UNIV_MEM_FREE(addr, size) VALGRIND_MAKE_MEM_NOACCESS(addr, size)
# define UNIV_MEM_ALLOC(addr, size) VALGRIND_MAKE_MEM_UNDEFINED(addr, size)
+# define UNIV_MEM_ASSERT_RW(addr, size) do { \
+ const void* _p = (const void*) \
+ VALGRIND_CHECK_MEM_IS_DEFINED(addr, size); \
+ if (UNIV_LIKELY_NULL(_p)) \
+ fprintf(stderr, "%s:%d: %p[%u] undefined at %d\n", \
+ __FILE__, __LINE__, \
+ (const void*) (addr), (unsigned) (size), \
+ ((const char*) _p) - ((const char*) (addr))); \
+ } while (0)
+# define UNIV_MEM_ASSERT_W(addr, size) do { \
+ const void* _p = (const void*) \
+ VALGRIND_CHECK_MEM_IS_ADDRESSABLE(addr, size); \
+ if (UNIV_LIKELY_NULL(_p)) \
+ fprintf(stderr, "%s:%d: %p[%u] unwritable at %d\n", \
+ __FILE__, __LINE__, \
+ (const void*) (addr), (unsigned) (size), \
+ ((const char*) _p) - ((const char*) (addr))); \
+ } while (0)
#else
# define UNIV_MEM_VALID(addr, size) do {} while(0)
# define UNIV_MEM_INVALID(addr, size) do {} while(0)
# define UNIV_MEM_FREE(addr, size) do {} while(0)
# define UNIV_MEM_ALLOC(addr, size) do {} while(0)
+# define UNIV_MEM_ASSERT_RW(addr, size) do {} while(0)
+# define UNIV_MEM_ASSERT_W(addr, size) do {} while(0)
#endif
+#define UNIV_MEM_ASSERT_AND_FREE(addr, size) do { \
+ UNIV_MEM_ASSERT_W(addr, size); \
+ UNIV_MEM_FREE(addr, size); \
+} while (0)
+#define UNIV_MEM_ASSERT_AND_ALLOC(addr, size) do { \
+ UNIV_MEM_ASSERT_W(addr, size); \
+ UNIV_MEM_ALLOC(addr, size); \
+} while (0)
#endif
diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h
index 825c10d5f11..a60ce73c35a 100644
--- a/storage/innobase/include/ut0ut.h
+++ b/storage/innobase/include/ut0ut.h
@@ -263,6 +263,24 @@ ut_copy_file(
FILE* dest, /* in: output file */
FILE* src); /* in: input file to be appended to output */
+/**************************************************************************
+snprintf(). */
+
+#ifdef __WIN__
+int
+ut_snprintf(
+ /* out: number of characters that would
+ have been printed if the size were
+ unlimited, not including the terminating
+ '\0'. */
+ char* str, /* out: string */
+ size_t size, /* in: str size */
+ const char* fmt, /* in: format */
+ ...); /* in: format values */
+#else
+#define ut_snprintf snprintf
+#endif /* __WIN__ */
+
#ifndef UNIV_NONINL
#include "ut0ut.ic"
#endif
diff --git a/storage/innobase/mem/mem0dbg.c b/storage/innobase/mem/mem0dbg.c
index eb77dd01f6d..72452907c3f 100644
--- a/storage/innobase/mem/mem0dbg.c
+++ b/storage/innobase/mem/mem0dbg.c
@@ -223,6 +223,8 @@ mem_init_buf(
{
byte* ptr;
+ UNIV_MEM_ASSERT_W(buf, n);
+
for (ptr = buf; ptr < buf + n; ptr++) {
if (ut_rnd_gen_ibool()) {
@@ -231,6 +233,8 @@ mem_init_buf(
*ptr = 0xBE;
}
}
+
+ UNIV_MEM_INVALID(buf, n);
}
/*******************************************************************
@@ -245,6 +249,8 @@ mem_erase_buf(
{
byte* ptr;
+ UNIV_MEM_ASSERT_W(buf, n);
+
for (ptr = buf; ptr < buf + n; ptr++) {
if (ut_rnd_gen_ibool()) {
*ptr = 0xDE;
@@ -252,6 +258,8 @@ mem_erase_buf(
*ptr = 0xAD;
}
}
+
+ UNIV_MEM_FREE(buf, n);
}
/*******************************************************************
@@ -546,9 +554,7 @@ completed:
}
*error = FALSE;
}
-#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
-#ifdef UNIV_DEBUG
/******************************************************************
Prints the contents of a memory heap. */
static
@@ -575,20 +581,6 @@ mem_heap_print(
}
/******************************************************************
-Checks that an object is a memory heap (or a block of it). */
-
-ibool
-mem_heap_check(
-/*===========*/
- /* out: TRUE if ok */
- mem_heap_t* heap) /* in: memory heap */
-{
- ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
-
- return(TRUE);
-}
-
-/******************************************************************
Validates the contents of a memory heap. */
ibool
@@ -614,6 +606,22 @@ mem_heap_validate(
return(TRUE);
}
+#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
+
+#ifdef UNIV_DEBUG
+/******************************************************************
+Checks that an object is a memory heap (or a block of it). */
+
+ibool
+mem_heap_check(
+/*===========*/
+ /* out: TRUE if ok */
+ mem_heap_t* heap) /* in: memory heap */
+{
+ ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
+
+ return(TRUE);
+}
#endif /* UNIV_DEBUG */
#ifdef UNIV_MEM_DEBUG
diff --git a/storage/innobase/mem/mem0mem.c b/storage/innobase/mem/mem0mem.c
index d89a3a55d88..f4fd178a39c 100644
--- a/storage/innobase/mem/mem0mem.c
+++ b/storage/innobase/mem/mem0mem.c
@@ -512,9 +512,9 @@ mem_heap_block_free(
of hex 0xDE and 0xAD. */
mem_erase_buf((byte*)block, len);
-
-#endif
- UNIV_MEM_FREE(block, len);
+#else /* UNIV_MEM_DEBUG */
+ UNIV_MEM_ASSERT_AND_FREE(block, len);
+#endif /* UNIV_MEM_DEBUG */
if (init_block) {
/* Do not have to free: do nothing */
diff --git a/storage/innobase/row/row0mysql.c b/storage/innobase/row/row0mysql.c
index b8d201e3da2..b3cf20b78b8 100644
--- a/storage/innobase/row/row0mysql.c
+++ b/storage/innobase/row/row0mysql.c
@@ -1728,10 +1728,11 @@ row_mysql_unlock_data_dictionary(
}
/*************************************************************************
-Does a table creation operation for MySQL. If the name of the table
-to be created is equal with one of the predefined magic table names,
-then this also starts printing the corresponding monitor output by
-the master thread. */
+Drops a table for MySQL. If the name of the table ends in
+one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
+"innodb_table_monitor", then this will also start the printing of monitor
+output by the master thread. If the table name ends in "innodb_mem_validate",
+InnoDB will try to invoke mem_validate(). */
int
row_create_table_for_mysql(
@@ -1756,13 +1757,11 @@ row_create_table_for_mysql(
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
if (srv_created_new_raw) {
- fputs("InnoDB: A new raw disk partition was initialized or\n"
- "InnoDB: innodb_force_recovery is on: we do not allow\n"
- "InnoDB: database modifications by the user. Shut down\n"
- "InnoDB: mysqld and edit my.cnf so that newraw"
- " is replaced\n"
- "InnoDB: with raw, and innodb_force_... is removed.\n",
- stderr);
+ fputs("InnoDB: A new raw disk partition was initialized:\n"
+ "InnoDB: we do not allow database modifications"
+ " by the user.\n"
+ "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
+ " is replaced with raw.\n", stderr);
dict_mem_table_free(table);
trx_commit_for_mysql(trx);
@@ -2703,13 +2702,11 @@ row_truncate_table_for_mysql(
ut_ad(table);
if (srv_created_new_raw) {
- fputs("InnoDB: A new raw disk partition was initialized or\n"
- "InnoDB: innodb_force_recovery is on: we do not allow\n"
- "InnoDB: database modifications by the user. Shut down\n"
- "InnoDB: mysqld and edit my.cnf so that newraw"
- " is replaced\n"
- "InnoDB: with raw, and innodb_force_... is removed.\n",
- stderr);
+ fputs("InnoDB: A new raw disk partition was initialized:\n"
+ "InnoDB: we do not allow database modifications"
+ " by the user.\n"
+ "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
+ " is replaced with raw.\n", stderr);
return(DB_ERROR);
}
@@ -2898,7 +2895,9 @@ next_rec:
/* MySQL calls ha_innobase::reset_auto_increment() which does
the same thing. */
+ dict_table_autoinc_lock(table);
dict_table_autoinc_initialize(table, 0);
+ dict_table_autoinc_unlock(table);
dict_update_statistics(table);
trx_commit_for_mysql(trx);
@@ -2916,9 +2915,10 @@ funct_exit:
#endif /* !UNIV_HOTBACKUP */
/*************************************************************************
-Drops a table for MySQL. If the name of the table to be dropped is equal
-with one of the predefined magic table names, then this also stops printing
-the corresponding monitor output by the master thread. */
+Drops a table for MySQL. If the name of the dropped table ends in
+one of "innodb_monitor", "innodb_lock_monitor", "innodb_tablespace_monitor",
+"innodb_table_monitor", then this will also stop the printing of monitor
+output by the master thread. */
int
row_drop_table_for_mysql(
@@ -2934,21 +2934,17 @@ row_drop_table_for_mysql(
ulint err;
const char* table_name;
ulint namelen;
- char* dir_path_of_temp_table = NULL;
- ibool success;
ibool locked_dictionary = FALSE;
pars_info_t* info = NULL;
ut_a(name != NULL);
if (srv_created_new_raw) {
- fputs("InnoDB: A new raw disk partition was initialized or\n"
- "InnoDB: innodb_force_recovery is on: we do not allow\n"
- "InnoDB: database modifications by the user. Shut down\n"
- "InnoDB: mysqld and edit my.cnf so that newraw"
- " is replaced\n"
- "InnoDB: with raw, and innodb_force_... is removed.\n",
- stderr);
+ fputs("InnoDB: A new raw disk partition was initialized:\n"
+ "InnoDB: we do not allow database modifications"
+ " by the user.\n"
+ "InnoDB: Shut down mysqld and edit my.cnf so that newraw"
+ " is replaced with raw.\n", stderr);
return(DB_ERROR);
}
@@ -3232,14 +3228,20 @@ check_next_foreign:
} else {
ibool is_path;
const char* name_or_path;
+ mem_heap_t* heap;
+ heap = mem_heap_create(200);
+
+ /* Clone the name, in case it has been allocated
+ from table->heap, which will be freed by
+ dict_table_remove_from_cache(table) below. */
+ name = mem_heap_strdup(heap, name);
space_id = table->space;
if (table->dir_path_of_temp_table != NULL) {
- dir_path_of_temp_table = mem_strdup(
- table->dir_path_of_temp_table);
is_path = TRUE;
- name_or_path = dir_path_of_temp_table;
+ name_or_path = mem_heap_strdup(
+ heap, table->dir_path_of_temp_table);
} else {
is_path = FALSE;
name_or_path = name;
@@ -3272,13 +3274,7 @@ check_next_foreign:
"InnoDB: of table ");
ut_print_name(stderr, trx, TRUE, name);
fprintf(stderr, ".\n");
-
- goto funct_exit;
- }
-
- success = fil_delete_tablespace(space_id);
-
- if (!success) {
+ } else if (!fil_delete_tablespace(space_id)) {
fprintf(stderr,
"InnoDB: We removed now the InnoDB"
" internal data dictionary entry\n"
@@ -3296,6 +3292,8 @@ check_next_foreign:
err = DB_ERROR;
}
}
+
+ mem_heap_free(heap);
}
funct_exit:
@@ -3305,10 +3303,6 @@ funct_exit:
row_mysql_unlock_data_dictionary(trx);
}
- if (dir_path_of_temp_table) {
- mem_free(dir_path_of_temp_table);
- }
-
trx->op_info = "";
#ifndef UNIV_HOTBACKUP
diff --git a/storage/innobase/row/row0sel.c b/storage/innobase/row/row0sel.c
index fdf6aa46351..51f76036aae 100644
--- a/storage/innobase/row/row0sel.c
+++ b/storage/innobase/row/row0sel.c
@@ -531,12 +531,13 @@ row_sel_build_prev_vers(
/*====================*/
/* out: DB_SUCCESS or error code */
read_view_t* read_view, /* in: read view */
- plan_t* plan, /* in: plan node for table */
+ dict_index_t* index, /* in: plan node for table */
rec_t* rec, /* in: record in a clustered index */
ulint** offsets, /* in/out: offsets returned by
rec_get_offsets(rec, plan->index) */
mem_heap_t** offset_heap, /* in/out: memory heap from which
the offsets are allocated */
+ mem_heap_t** old_vers_heap, /* out: old version heap to use */
rec_t** old_vers, /* out: old version, or NULL if the
record does not exist in the view:
i.e., it was freshly inserted
@@ -545,15 +546,15 @@ row_sel_build_prev_vers(
{
ulint err;
- if (plan->old_vers_heap) {
- mem_heap_empty(plan->old_vers_heap);
+ if (*old_vers_heap) {
+ mem_heap_empty(*old_vers_heap);
} else {
- plan->old_vers_heap = mem_heap_create(512);
+ *old_vers_heap = mem_heap_create(512);
}
err = row_vers_build_for_consistent_read(
- rec, mtr, plan->index, offsets, read_view, offset_heap,
- plan->old_vers_heap, old_vers);
+ rec, mtr, index, offsets, read_view, offset_heap,
+ *old_vers_heap, old_vers);
return(err);
}
@@ -765,9 +766,11 @@ row_sel_get_clust_rec(
if (!lock_clust_rec_cons_read_sees(clust_rec, index, offsets,
node->read_view)) {
- err = row_sel_build_prev_vers(node->read_view, plan,
- clust_rec, &offsets,
- &heap, &old_vers, mtr);
+ err = row_sel_build_prev_vers(
+ node->read_view, index, clust_rec,
+ &offsets, &heap, &plan->old_vers_heap,
+ &old_vers, mtr);
+
if (err != DB_SUCCESS) {
goto err_exit;
@@ -1490,10 +1493,11 @@ skip_lock:
if (!lock_clust_rec_cons_read_sees(rec, index, offsets,
node->read_view)) {
- err = row_sel_build_prev_vers(node->read_view,
- plan, rec,
- &offsets, &heap,
- &old_vers, &mtr);
+ err = row_sel_build_prev_vers(
+ node->read_view, index, rec,
+ &offsets, &heap, &plan->old_vers_heap,
+ &old_vers, &mtr);
+
if (err != DB_SUCCESS) {
goto lock_wait_or_error;
@@ -3999,6 +4003,7 @@ no_gap_lock:
mutex_enter(&kernel_mutex);
if (trx->was_chosen_as_deadlock_victim) {
mutex_exit(&kernel_mutex);
+ err = DB_DEADLOCK;
goto lock_wait_or_error;
}
@@ -4536,6 +4541,7 @@ row_search_autoinc_read_column(
const byte* data;
ib_longlong value;
mem_heap_t* heap = NULL;
+ /* Our requirement is that dest should be word aligned. */
byte dest[sizeof(value)];
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
@@ -4554,20 +4560,35 @@ row_search_autoinc_read_column(
ut_a(len != UNIV_SQL_NULL);
ut_a(len <= sizeof value);
- /* Copy integer data and restore sign bit */
- if (unsigned_type || (data[0] & 128))
- memset(dest, 0x00, sizeof(dest));
- else
- memset(dest, 0xff, sizeof(dest));
+ mach_read_int_type(dest, data, len, unsigned_type);
+
+ /* The assumption here is that the AUTOINC value can't be negative
+ and that dest is word aligned. */
+ switch (len) {
+ case 8:
+ value = *(ib_longlong*) dest;
+ break;
- memcpy(dest + (sizeof(value) - len), data, len);
+ case 4:
+ value = *(ib_uint32_t*) dest;
+ break;
- if (!unsigned_type)
- dest[sizeof(value) - len] ^= 128;
+ case 3:
+ value = *(ib_uint32_t*) dest;
+ value &= 0xFFFFFF;
+ break;
- /* The assumption here is that the AUTOINC value can't be negative.*/
- value = (((ib_longlong) mach_read_from_4(dest)) << 32) |
- ((ib_longlong) mach_read_from_4(dest + 4));
+ case 2:
+ value = *(uint16 *) dest;
+ break;
+
+ case 1:
+ value = *dest;
+ break;
+
+ default:
+ ut_error;
+ }
if (UNIV_LIKELY_NULL(heap)) {
mem_heap_free(heap);
diff --git a/storage/innobase/sync/sync0rw.c b/storage/innobase/sync/sync0rw.c
index 4db780c8b3f..8dbc69816e9 100644
--- a/storage/innobase/sync/sync0rw.c
+++ b/storage/innobase/sync/sync0rw.c
@@ -174,9 +174,7 @@ rw_lock_free(
/*=========*/
rw_lock_t* lock) /* in: rw-lock */
{
-#ifdef UNIV_DEBUG
- ut_a(rw_lock_validate(lock));
-#endif /* UNIV_DEBUG */
+ ut_ad(rw_lock_validate(lock));
ut_a(rw_lock_get_writer(lock) == RW_LOCK_NOT_LOCKED);
ut_a(rw_lock_get_waiters(lock) == 0);
ut_a(rw_lock_get_reader_count(lock) == 0);
@@ -199,6 +197,7 @@ rw_lock_free(
mutex_exit(&rw_lock_list_mutex);
}
+#ifdef UNIV_DEBUG
/**********************************************************************
Checks that the rw-lock has been initialized and that there are no
simultaneous shared and exclusive locks. */
@@ -226,6 +225,7 @@ rw_lock_validate(
return(TRUE);
}
+#endif /* UNIV_DEBUG */
/**********************************************************************
Lock an rw-lock in shared mode for the current thread. If the rw-lock is
diff --git a/storage/innobase/ut/ut0ut.c b/storage/innobase/ut/ut0ut.c
index 389063ad821..1ca278cd633 100644
--- a/storage/innobase/ut/ut0ut.c
+++ b/storage/innobase/ut/ut0ut.c
@@ -18,6 +18,7 @@ Created 5/11/1994 Heikki Tuuri
#include "ut0sort.h"
#include "trx0trx.h"
+#include "ha_prototypes.h"
ibool ut_always_false = FALSE;
@@ -70,22 +71,6 @@ ut_gettimeofday(
#define ut_gettimeofday gettimeofday
#endif
-#ifndef UNIV_HOTBACKUP
-/*********************************************************************
-Display an SQL identifier.
-This definition must match the one in sql/ha_innodb.cc! */
-extern
-void
-innobase_print_identifier(
-/*======================*/
- FILE* f, /* in: output stream */
- trx_t* trx, /* in: transaction */
- ibool table_id,/* in: TRUE=print a table name,
- FALSE=print other identifier */
- const char* name, /* in: name to print */
- ulint namelen);/* in: length of name */
-#endif /* !UNIV_HOTBACKUP */
-
/************************************************************
Gets the high 32 bits in a ulint. That is makes a shift >> 32,
but since there seem to be compiler bugs in both gcc and Visual C++,
@@ -360,6 +345,8 @@ ut_print_buf(
const byte* data;
ulint i;
+ UNIV_MEM_ASSERT_RW(buf, len);
+
fprintf(file, " len %lu; hex ", len);
for (data = (const byte*)buf, i = 0; i < len; i++) {
@@ -474,17 +461,20 @@ ut_print_namel(
#ifdef UNIV_HOTBACKUP
fwrite(name, 1, namelen, f);
#else
- char* slash = memchr(name, '/', namelen);
+ if (table_id) {
+ char* slash = memchr(name, '/', namelen);
+ if (!slash) {
- if (UNIV_LIKELY_NULL(slash)) {
- /* Print the database name and table name separately. */
- ut_ad(table_id);
+ goto no_db_name;
+ }
+ /* Print the database name and table name separately. */
innobase_print_identifier(f, trx, TRUE, name, slash - name);
putc('.', f);
innobase_print_identifier(f, trx, TRUE, slash + 1,
namelen - (slash - name) - 1);
} else {
+no_db_name:
innobase_print_identifier(f, trx, table_id, name, namelen);
}
#endif
@@ -515,3 +505,44 @@ ut_copy_file(
}
} while (len > 0);
}
+
+/**************************************************************************
+snprintf(). */
+
+#ifdef __WIN__
+#include <stdarg.h>
+int
+ut_snprintf(
+ /* out: number of characters that would
+ have been printed if the size were
+ unlimited, not including the terminating
+ '\0'. */
+ char* str, /* out: string */
+ size_t size, /* in: str size */
+ const char* fmt, /* in: format */
+ ...) /* in: format values */
+{
+ int res;
+ va_list ap1;
+ va_list ap2;
+
+ va_start(ap1, fmt);
+ va_start(ap2, fmt);
+
+ res = _vscprintf(fmt, ap1);
+ ut_a(res != -1);
+
+ if (size > 0) {
+ _vsnprintf(str, size, fmt, ap2);
+
+ if ((size_t) res >= size) {
+ str[size - 1] = '\0';
+ }
+ }
+
+ va_end(ap1);
+ va_end(ap2);
+
+ return(res);
+}
+#endif /* __WIN__ */