summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJan Lindström <jan.lindstrom@mariadb.com>2016-09-06 09:43:16 +0300
committerJan Lindström <jan.lindstrom@mariadb.com>2016-09-08 15:49:03 +0300
commitfec844aca88e1c6b9c36bb0b811e92d9d023ffb9 (patch)
tree3e8602113e591b163bf23fffe95c8908cac88ea3
parent2e814d4702d71a04388386a9f591d14a35980bfe (diff)
downloadmariadb-git-fec844aca88e1c6b9c36bb0b811e92d9d023ffb9.tar.gz
Merge InnoDB 5.7 from mysql-5.7.14.
Contains also: MDEV-10549 mysqld: sql/handler.cc:2692: int handler::ha_index_first(uchar*): Assertion `table_share->tmp_table != NO_TMP_TABLE || m_lock_type != 2' failed. (branch bb-10.2-jan) Unlike MySQL, InnoDB still uses THR_LOCK in MariaDB MDEV-10548 Some of the debug sync waits do not work with InnoDB 5.7 (branch bb-10.2-jan) enable tests that were fixed in MDEV-10549 MDEV-10548 Some of the debug sync waits do not work with InnoDB 5.7 (branch bb-10.2-jan) fix main.innodb_mysql_sync - re-enable online alter for partitioned innodb tables
-rw-r--r--include/my_base.h13
-rw-r--r--include/my_handler_errors.h13
-rw-r--r--mysql-test/disabled.def4
-rw-r--r--mysql-test/include/have_no_undo_tablespaces.inc4
-rw-r--r--mysql-test/include/mix1.inc9
-rw-r--r--mysql-test/r/partition_innodb_plugin.result1
-rw-r--r--mysql-test/suite/galera/r/create.result4
-rw-r--r--mysql-test/suite/handler/disabled.def2
-rw-r--r--mysql-test/suite/handler/innodb.result1
-rw-r--r--mysql-test/suite/innodb/disabled.def2
-rw-r--r--mysql-test/suite/innodb/include/show_i_s_tablespaces.inc38
-rw-r--r--mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result1
-rw-r--r--mysql-test/suite/innodb/r/innodb_information_schema.result8
-rw-r--r--mysql-test/suite/innodb/r/innodb_mysql.result4
-rw-r--r--mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test1
-rw-r--r--mysql-test/suite/innodb/t/innodb.test2
-rw-r--r--mysql-test/suite/innodb/t/innodb_mysql-master.opt4
-rw-r--r--mysql-test/suite/innodb/t/innodb_simulate_comp_failures.test1
-rw-r--r--mysql-test/suite/innodb_zip/r/16k.result150
-rw-r--r--mysql-test/suite/innodb_zip/r/wl6347_comp_indx_stat.result6
-rw-r--r--mysql-test/suite/innodb_zip/r/wl6560.result418
-rw-r--r--mysql-test/suite/innodb_zip/r/wl6915_1.result39
-rw-r--r--mysql-test/suite/innodb_zip/t/16k-master.opt3
-rw-r--r--mysql-test/suite/innodb_zip/t/16k.test8
-rw-r--r--mysql-test/suite/innodb_zip/t/disabled.def2
-rw-r--r--mysql-test/suite/innodb_zip/t/large_blob.test2
-rw-r--r--mysql-test/suite/innodb_zip/t/wl6560.test7
-rw-r--r--mysql-test/suite/innodb_zip/t/wl6915_1.test4
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result78
-rw-r--r--mysql-test/suite/sys_vars/r/innodb_support_xa_func.result16
-rw-r--r--mysql-test/t/partition_innodb_plugin.test2
-rw-r--r--mysql-test/t/row-checksum.opt1
-rw-r--r--sql/handler.cc16
-rw-r--r--sql/share/errmsg-utf8.txt18
-rw-r--r--storage/innobase/CMakeLists.txt405
-rw-r--r--storage/innobase/api/api0api.cc24
-rw-r--r--storage/innobase/api/api0misc.cc64
-rw-r--r--storage/innobase/btr/btr0btr.cc186
-rw-r--r--storage/innobase/btr/btr0bulk.cc37
-rw-r--r--storage/innobase/btr/btr0cur.cc224
-rw-r--r--storage/innobase/btr/btr0defragment.cc30
-rw-r--r--storage/innobase/btr/btr0scrub.cc5
-rw-r--r--storage/innobase/btr/btr0sea.cc26
-rw-r--r--storage/innobase/buf/buf0buf.cc386
-rw-r--r--storage/innobase/buf/buf0checksum.cc6
-rw-r--r--storage/innobase/buf/buf0dblwr.cc13
-rw-r--r--storage/innobase/buf/buf0dump.cc44
-rw-r--r--storage/innobase/buf/buf0flu.cc176
-rw-r--r--storage/innobase/buf/buf0lru.cc57
-rw-r--r--storage/innobase/buf/buf0mtflu.cc2
-rw-r--r--storage/innobase/buf/buf0rea.cc13
-rw-r--r--storage/innobase/data/data0data.cc3
-rw-r--r--storage/innobase/dict/dict0boot.cc2
-rw-r--r--storage/innobase/dict/dict0crea.cc203
-rw-r--r--storage/innobase/dict/dict0defrag_bg.cc403
-rw-r--r--storage/innobase/dict/dict0dict.cc318
-rw-r--r--storage/innobase/dict/dict0load.cc280
-rw-r--r--storage/innobase/dict/dict0mem.cc285
-rw-r--r--storage/innobase/dict/dict0stats.cc149
-rw-r--r--storage/innobase/dict/dict0stats_bg.cc274
-rw-r--r--storage/innobase/fil/fil0crypt.cc2
-rw-r--r--storage/innobase/fil/fil0fil.cc1088
-rw-r--r--storage/innobase/fsp/fsp0file.cc132
-rw-r--r--storage/innobase/fsp/fsp0fsp.cc607
-rw-r--r--storage/innobase/fsp/fsp0space.cc30
-rw-r--r--storage/innobase/fsp/fsp0sysspace.cc27
-rw-r--r--storage/innobase/fts/fts0ast.cc34
-rw-r--r--storage/innobase/fts/fts0fts.cc103
-rw-r--r--storage/innobase/fts/fts0opt.cc54
-rw-r--r--storage/innobase/fts/fts0que.cc63
-rw-r--r--storage/innobase/gis/gis0rtree.cc139
-rw-r--r--storage/innobase/gis/gis0sea.cc123
-rw-r--r--storage/innobase/handler/ha_innodb.cc2872
-rw-r--r--storage/innobase/handler/ha_innodb.h664
-rw-r--r--storage/innobase/handler/ha_innopart.cc245
-rw-r--r--storage/innobase/handler/ha_innopart.h22
-rw-r--r--storage/innobase/handler/handler0alter.cc1569
-rw-r--r--storage/innobase/handler/i_s.cc461
-rw-r--r--storage/innobase/ibuf/ibuf0ibuf.cc69
-rw-r--r--storage/innobase/include/api0api.h9
-rw-r--r--storage/innobase/include/btr0btr.h47
-rw-r--r--storage/innobase/include/btr0bulk.h2
-rw-r--r--storage/innobase/include/btr0sea.h7
-rw-r--r--storage/innobase/include/btr0sea.ic6
-rw-r--r--storage/innobase/include/btr0types.h2
-rw-r--r--storage/innobase/include/buf0buf.h65
-rw-r--r--storage/innobase/include/buf0buf.ic71
-rw-r--r--storage/innobase/include/buf0checksum.h7
-rw-r--r--storage/innobase/include/buf0dblwr.h4
-rw-r--r--storage/innobase/include/buf0flu.h29
-rw-r--r--storage/innobase/include/buf0rea.h7
-rw-r--r--storage/innobase/include/data0data.h38
-rw-r--r--storage/innobase/include/data0data.ic31
-rw-r--r--storage/innobase/include/db0err.h13
-rw-r--r--storage/innobase/include/dict0crea.h14
-rw-r--r--storage/innobase/include/dict0defrag_bg.h93
-rw-r--r--storage/innobase/include/dict0dict.h137
-rw-r--r--storage/innobase/include/dict0dict.ic101
-rw-r--r--storage/innobase/include/dict0load.h10
-rw-r--r--storage/innobase/include/dict0mem.h185
-rw-r--r--storage/innobase/include/dict0stats.h36
-rw-r--r--storage/innobase/include/dict0stats_bg.h46
-rw-r--r--storage/innobase/include/dict0types.h29
-rw-r--r--storage/innobase/include/dyn0buf.h22
-rw-r--r--storage/innobase/include/fil0crypt.ic2
-rw-r--r--storage/innobase/include/fil0fil.h472
-rw-r--r--storage/innobase/include/fsp0file.h42
-rw-r--r--storage/innobase/include/fsp0fsp.h117
-rw-r--r--storage/innobase/include/fsp0fsp.ic27
-rw-r--r--storage/innobase/include/fsp0space.h21
-rw-r--r--storage/innobase/include/fsp0sysspace.h24
-rw-r--r--storage/innobase/include/fsp0types.h30
-rw-r--r--storage/innobase/include/fts0ast.h7
-rw-r--r--storage/innobase/include/fts0fts.h95
-rw-r--r--storage/innobase/include/fts0priv.h56
-rw-r--r--storage/innobase/include/fts0priv.ic17
-rw-r--r--storage/innobase/include/fut0fut.h4
-rw-r--r--storage/innobase/include/gis0rtree.h21
-rw-r--r--storage/innobase/include/ha0ha.h2
-rw-r--r--storage/innobase/include/ha_prototypes.h16
-rw-r--r--storage/innobase/include/ibuf0ibuf.h8
-rw-r--r--storage/innobase/include/lock0lock.h48
-rw-r--r--storage/innobase/include/lock0prdt.h23
-rw-r--r--storage/innobase/include/lock0priv.h75
-rw-r--r--storage/innobase/include/log0log.h72
-rw-r--r--storage/innobase/include/log0log.ic7
-rw-r--r--storage/innobase/include/log0recv.h16
-rw-r--r--storage/innobase/include/mach0data.h29
-rw-r--r--storage/innobase/include/mach0data.ic2
-rw-r--r--storage/innobase/include/mem0mem.h2
-rw-r--r--storage/innobase/include/mem0mem.ic2
-rw-r--r--storage/innobase/include/mtr0log.ic24
-rw-r--r--storage/innobase/include/mtr0mtr.h44
-rw-r--r--storage/innobase/include/mtr0mtr.ic2
-rw-r--r--storage/innobase/include/os0atomic.h79
-rw-r--r--storage/innobase/include/os0atomic.ic11
-rw-r--r--storage/innobase/include/os0file.h358
-rw-r--r--storage/innobase/include/os0file.ic11
-rw-r--r--storage/innobase/include/os0thread.h9
-rw-r--r--storage/innobase/include/page0cur.h3
-rw-r--r--storage/innobase/include/page0page.h24
-rw-r--r--storage/innobase/include/page0types.h15
-rw-r--r--storage/innobase/include/page0zip.h52
-rw-r--r--storage/innobase/include/page0zip.ic3
-rw-r--r--storage/innobase/include/pars0pars.h18
-rw-r--r--storage/innobase/include/que0que.h16
-rw-r--r--storage/innobase/include/read0read.h2
-rw-r--r--storage/innobase/include/read0types.h4
-rw-r--r--storage/innobase/include/rem0cmp.h21
-rw-r--r--storage/innobase/include/rem0rec.h81
-rw-r--r--storage/innobase/include/rem0rec.ic2
-rw-r--r--storage/innobase/include/row0ftsort.h2
-rw-r--r--storage/innobase/include/row0ins.h8
-rw-r--r--storage/innobase/include/row0log.h17
-rw-r--r--storage/innobase/include/row0merge.h86
-rw-r--r--storage/innobase/include/row0mysql.h72
-rw-r--r--storage/innobase/include/row0purge.h2
-rw-r--r--storage/innobase/include/row0row.h10
-rw-r--r--storage/innobase/include/row0sel.h9
-rw-r--r--storage/innobase/include/row0umod.h2
-rw-r--r--storage/innobase/include/row0undo.h4
-rw-r--r--storage/innobase/include/row0upd.h62
-rw-r--r--storage/innobase/include/row0vers.h9
-rw-r--r--storage/innobase/include/srv0mon.h10
-rw-r--r--storage/innobase/include/srv0srv.h34
-rw-r--r--storage/innobase/include/srv0start.h11
-rw-r--r--storage/innobase/include/sync0arr.h6
-rw-r--r--storage/innobase/include/sync0rw.h14
-rw-r--r--storage/innobase/include/sync0sync.h5
-rw-r--r--storage/innobase/include/sync0types.h7
-rw-r--r--storage/innobase/include/trx0rec.h4
-rw-r--r--storage/innobase/include/trx0rseg.h7
-rw-r--r--storage/innobase/include/trx0sys.h21
-rw-r--r--storage/innobase/include/trx0sys.ic8
-rw-r--r--storage/innobase/include/trx0trx.h62
-rw-r--r--storage/innobase/include/trx0types.h2
-rw-r--r--storage/innobase/include/trx0undo.h11
-rw-r--r--storage/innobase/include/univ.i46
-rw-r--r--storage/innobase/include/ut0counter.h8
-rw-r--r--storage/innobase/include/ut0crc32.h2
-rw-r--r--storage/innobase/include/ut0dbg.h2
-rw-r--r--storage/innobase/include/ut0lst.h1
-rw-r--r--storage/innobase/include/ut0mem.h2
-rw-r--r--storage/innobase/include/ut0new.h11
-rw-r--r--storage/innobase/include/ut0rnd.h2
-rw-r--r--storage/innobase/include/ut0rnd.ic2
-rw-r--r--storage/innobase/include/ut0ut.h35
-rw-r--r--storage/innobase/include/ut0wqueue.h1
-rw-r--r--storage/innobase/innodb.cmake272
-rw-r--r--storage/innobase/lock/lock0lock.cc940
-rw-r--r--storage/innobase/lock/lock0prdt.cc33
-rw-r--r--storage/innobase/lock/lock0wait.cc14
-rw-r--r--storage/innobase/log/log0crypt.cc2
-rw-r--r--storage/innobase/log/log0log.cc336
-rw-r--r--storage/innobase/log/log0recv.cc847
-rw-r--r--storage/innobase/mtr/mtr0log.cc14
-rw-r--r--storage/innobase/mtr/mtr0mtr.cc193
-rw-r--r--storage/innobase/os/os0file.cc1238
-rw-r--r--storage/innobase/os/os0sync.cc935
-rw-r--r--storage/innobase/os/os0thread.cc15
-rw-r--r--storage/innobase/page/page0zip.cc87
-rw-r--r--storage/innobase/pars/lexyy.cc2
-rw-r--r--storage/innobase/pars/pars0pars.cc21
-rw-r--r--storage/innobase/que/que0que.cc19
-rw-r--r--storage/innobase/rem/rem0cmp.cc58
-rw-r--r--storage/innobase/rem/rem0rec.cc15
-rw-r--r--storage/innobase/row/row0ftsort.cc30
-rw-r--r--storage/innobase/row/row0import.cc303
-rw-r--r--storage/innobase/row/row0ins.cc160
-rw-r--r--storage/innobase/row/row0log.cc51
-rw-r--r--storage/innobase/row/row0merge.cc252
-rw-r--r--storage/innobase/row/row0mysql.cc239
-rw-r--r--storage/innobase/row/row0purge.cc33
-rw-r--r--storage/innobase/row/row0quiesce.cc245
-rw-r--r--storage/innobase/row/row0row.cc16
-rw-r--r--storage/innobase/row/row0sel.cc82
-rw-r--r--storage/innobase/row/row0trunc.cc64
-rw-r--r--storage/innobase/row/row0uins.cc2
-rw-r--r--storage/innobase/row/row0umod.cc30
-rw-r--r--storage/innobase/row/row0undo.cc2
-rw-r--r--storage/innobase/row/row0upd.cc313
-rw-r--r--storage/innobase/row/row0vers.cc242
-rw-r--r--storage/innobase/srv/srv0conc.cc13
-rw-r--r--storage/innobase/srv/srv0mon.cc7
-rw-r--r--storage/innobase/srv/srv0srv.cc166
-rw-r--r--storage/innobase/srv/srv0start.cc136
-rw-r--r--storage/innobase/sync/sync0arr.cc26
-rw-r--r--storage/innobase/sync/sync0debug.cc17
-rw-r--r--storage/innobase/sync/sync0rw.cc46
-rw-r--r--storage/innobase/sync/sync0sync.cc10
-rw-r--r--storage/innobase/trx/trx0i_s.cc1
-rw-r--r--storage/innobase/trx/trx0purge.cc13
-rw-r--r--storage/innobase/trx/trx0rec.cc161
-rw-r--r--storage/innobase/trx/trx0roll.cc18
-rw-r--r--storage/innobase/trx/trx0rseg.cc30
-rw-r--r--storage/innobase/trx/trx0sys.cc225
-rw-r--r--storage/innobase/trx/trx0trx.cc226
-rw-r--r--storage/innobase/trx/trx0undo.cc21
-rw-r--r--storage/innobase/ut/ut0crc32.cc2
-rw-r--r--storage/innobase/ut/ut0dbg.cc6
-rw-r--r--storage/innobase/ut/ut0new.cc4
-rw-r--r--storage/innobase/ut/ut0rnd.cc2
-rw-r--r--storage/innobase/ut/ut0ut.cc34
-rw-r--r--storage/innobase/ut/ut0wqueue.cc1
244 files changed, 15626 insertions, 9069 deletions
diff --git a/include/my_base.h b/include/my_base.h
index 1317639c528..af053369f93 100644
--- a/include/my_base.h
+++ b/include/my_base.h
@@ -499,7 +499,18 @@ enum ha_base_keytype {
#define HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE 191 /* Too many words in a phrase */
#define HA_ERR_DECRYPTION_FAILED 192 /* Table encrypted but
decypt failed */
-#define HA_ERR_LAST 192 /* Copy of last error nr */
+#define HA_ERR_FK_DEPTH_EXCEEDED 193 /* FK cascade depth exceeded */
+#define HA_MISSING_CREATE_OPTION 194 /* Option Missing during Create */
+#define HA_ERR_SE_OUT_OF_MEMORY 195 /* Out of memory in storage engine */
+#define HA_ERR_TABLE_CORRUPT 196 /* Table/Clustered index is corrupted. */
+#define HA_ERR_QUERY_INTERRUPTED 197 /* The query was interrupted */
+#define HA_ERR_TABLESPACE_MISSING 198 /* Missing Tablespace */
+#define HA_ERR_TABLESPACE_IS_NOT_EMPTY 199 /* Tablespace is not empty */
+#define HA_ERR_WRONG_FILE_NAME 200 /* Invalid Filename */
+#define HA_ERR_NOT_ALLOWED_COMMAND 201 /* Operation is not allowed */
+#define HA_ERR_COMPUTE_FAILED 202 /* Compute generated column value failed */
+#define HA_ERR_INNODB_READ_ONLY 203 /* InnoDB is in read only mode */
+#define HA_ERR_LAST 203 /* Copy of last error nr * */
/* Number of different errors */
#define HA_ERR_ERRORS (HA_ERR_LAST - HA_ERR_FIRST + 1)
diff --git a/include/my_handler_errors.h b/include/my_handler_errors.h
index 5af6a359348..3d05fb75054 100644
--- a/include/my_handler_errors.h
+++ b/include/my_handler_errors.h
@@ -95,7 +95,18 @@ static const char *handler_error_messages[]=
"Disk full",
"Incompatible key or row definition between the MariaDB .frm file and the information in the storage engine. You have to dump and restore the table to fix this",
"Too many words in a FTS phrase or proximity search",
- "Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match."
+ "Table encrypted but decryption failed. This could be because correct encryption management plugin is not loaded, used encryption key is not available or encryption method does not match.",
+ "Foreign key cascade delete/update exceeds max depth",
+ "Table storage engine found required create option missing",
+ "Out of memory in storage engine",
+ "Operation cannot be performed. The table is missing, corrupt or contains bad data.",
+ "Query execution was interrupted",
+ "Tablespace is missing for table",
+ "Tablespace is not empty",
+ "Incorrect File Name",
+ "Table storage engine found required create option missing",
+ "Compute virtual column value failed",
+ "InnoDB is in read only mode"
};
#endif /* MYSYS_MY_HANDLER_ERRORS_INCLUDED */
diff --git a/mysql-test/disabled.def b/mysql-test/disabled.def
index 75704c7571e..e82ddcf92d1 100644
--- a/mysql-test/disabled.def
+++ b/mysql-test/disabled.def
@@ -22,7 +22,3 @@ innodb-wl5522-debug-zip : broken upstream
innodb_bug12902967 : broken upstream
file_contents : MDEV-6526 these files are not installed anymore
max_statement_time : cannot possibly work, depends on timing
-implicit_commit : MDEV-10549
-lock_sync : MDEV-10548
-innodb_mysql_sync : MDEV-10548
-partition_debug_sync : MDEV-10548
diff --git a/mysql-test/include/have_no_undo_tablespaces.inc b/mysql-test/include/have_no_undo_tablespaces.inc
new file mode 100644
index 00000000000..4c163e7c1b0
--- /dev/null
+++ b/mysql-test/include/have_no_undo_tablespaces.inc
@@ -0,0 +1,4 @@
+if (`select count(*) = 0 from information_schema.global_variables where variable_name like 'innodb_undo_tablespaces' and variable_value = 0`)
+{
+ --skip Test requires innodb_undo_tablespaces=0
+}
diff --git a/mysql-test/include/mix1.inc b/mysql-test/include/mix1.inc
index bfe1567691d..7eae4235baa 100644
--- a/mysql-test/include/mix1.inc
+++ b/mysql-test/include/mix1.inc
@@ -624,6 +624,11 @@ DROP TABLE t1,t2,t3;
# Test bug when trying to drop data file which no InnoDB directory entry
#
+--disable_query_log
+call mtr.add_suppression("InnoDB: Table .*bug29807.*");
+call mtr.add_suppression("InnoDB: Cannot open table test/bug29807 from");
+--enable_query_log
+
create table t1 (a int) engine=innodb;
let $MYSQLD_DATADIR= `select @@datadir`;
copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/bug29807.frm;
@@ -631,10 +636,6 @@ copy_file $MYSQLD_DATADIR/test/t1.frm $MYSQLD_DATADIR/test/bug29807.frm;
select * from bug29807;
drop table t1;
drop table bug29807;
---disable_query_log
-call mtr.add_suppression("InnoDB: Error: table .test...bug29807. does not exist in the InnoDB internal");
-call mtr.add_suppression("InnoDB: Cannot open table test/bug29807 from");
---enable_query_log
#
diff --git a/mysql-test/r/partition_innodb_plugin.result b/mysql-test/r/partition_innodb_plugin.result
index 35b1e3142b4..16b5daad620 100644
--- a/mysql-test/r/partition_innodb_plugin.result
+++ b/mysql-test/r/partition_innodb_plugin.result
@@ -1,3 +1,4 @@
+call mtr.add_suppression("InnoDB: Table .* does not exist in the InnoDB internal data dictionary .*");
#
# Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB,
# PARTITONING, ON INDEX CREATE
diff --git a/mysql-test/suite/galera/r/create.result b/mysql-test/suite/galera/r/create.result
index b93cd7b9496..4d6488d324b 100644
--- a/mysql-test/suite/galera/r/create.result
+++ b/mysql-test/suite/galera/r/create.result
@@ -76,13 +76,17 @@ DROP TABLE t1, t2;
# MDEV-10235: Deadlock in CREATE TABLE ... AS SELECT .. if result set
# is empty in Galera
#
+connection node_1;
CREATE TABLE t1(c1 INT) ENGINE=INNODB;
INSERT INTO t1 VALUES(1);
CREATE TABLE t2 AS SELECT * FROM t1 WHERE c1=2;
+connection node_2;
SELECT * FROM t1;
c1
1
SELECT * FROM t2;
c1
DROP TABLE t1, t2;
+disconnect node_2;
+disconnect node_1;
# End of tests
diff --git a/mysql-test/suite/handler/disabled.def b/mysql-test/suite/handler/disabled.def
index ef63577b0cb..888298bbb09 100644
--- a/mysql-test/suite/handler/disabled.def
+++ b/mysql-test/suite/handler/disabled.def
@@ -9,5 +9,3 @@
# Do not use any TAB characters for whitespace.
#
##############################################################################
-
-innodb : MDEV-10549 \ No newline at end of file
diff --git a/mysql-test/suite/handler/innodb.result b/mysql-test/suite/handler/innodb.result
index 102237617fd..f3c0f798902 100644
--- a/mysql-test/suite/handler/innodb.result
+++ b/mysql-test/suite/handler/innodb.result
@@ -545,6 +545,7 @@ optimize table t1;
connection default;
handler t1 read next;
c1
+1
handler t1 close;
connection con2;
Table Op Msg_type Msg_text
diff --git a/mysql-test/suite/innodb/disabled.def b/mysql-test/suite/innodb/disabled.def
index 778ce482db5..86fb2946bc9 100644
--- a/mysql-test/suite/innodb/disabled.def
+++ b/mysql-test/suite/innodb/disabled.def
@@ -12,5 +12,5 @@
innodb.auto_increment_dup : MDEV-10548
innodb_skip_innodb_is_tables : MDEV-10200
-innodb.innodb_bug13510739: MDEV-10549
innodb.defrag_mdl-9155 : MDEV-10551
+innodb_defragment_fill_factor : MDEV-10771 \ No newline at end of file
diff --git a/mysql-test/suite/innodb/include/show_i_s_tablespaces.inc b/mysql-test/suite/innodb/include/show_i_s_tablespaces.inc
new file mode 100644
index 00000000000..a79bc3c01a8
--- /dev/null
+++ b/mysql-test/suite/innodb/include/show_i_s_tablespaces.inc
@@ -0,0 +1,38 @@
+# This script assumes that the caller did the following;
+# LET $MYSQLD_DATADIR = `select @@datadir`;
+# LET $INNODB_PAGE_SIZE = `select @@innodb_page_size`;
+--echo === information_schema.innodb_sys_tablespaces and innodb_sys_datafiles ===
+--disable_query_log
+--replace_regex /#P#/#p#/ /#SP#/#sp#/
+--replace_result ./ MYSQLD_DATADIR/ $MYSQLD_DATADIR/ MYSQLD_DATADIR/ $MYSQLD_DATADIR MYSQLD_DATADIR/ $MYSQL_TMP_DIR MYSQL_TMP_DIR $INNODB_PAGE_SIZE DEFAULT
+SELECT s.name 'Space_Name',
+ s.space_type 'Space_Type',
+ s.page_size 'Page_Size',
+ s.zip_page_size 'Zip_Size',
+ s.row_format 'Formats_Permitted',
+ d.path 'Path'
+ FROM information_schema.innodb_sys_tablespaces s,
+ information_schema.innodb_sys_datafiles d
+ WHERE s.space = d.space
+ AND s.name NOT LIKE 'mysql/%'
+ AND s.name NOT LIKE 'sys/%'
+ ORDER BY s.space;
+
+# This SELECT will not show UNDO or TEMPORARY tablespaces since
+# they are only in FILES, not SYS_TABLESPACES.
+--echo === information_schema.files ===
+--replace_regex /innodb_file_per_table.[0-9]+/innodb_file_per_table.##/ /#P#/#p#/ /#SP#/#sp#/
+--replace_result ./ MYSQLD_DATADIR/ $MYSQLD_DATADIR/ MYSQLD_DATADIR/ $MYSQLD_DATADIR MYSQLD_DATADIR/ $MYSQL_TMP_DIR MYSQL_TMP_DIR $INNODB_PAGE_SIZE DEFAULT
+SELECT s.name 'Space_Name',
+ f.file_type 'File_Type',
+ f.engine 'Engine',
+ f.status 'Status',
+ f.tablespace_name 'Tablespace_Name',
+ f.file_name 'Path'
+ FROM information_schema.files f,
+ information_schema.innodb_sys_tablespaces s
+ WHERE f.file_id = s.space
+ AND s.name NOT LIKE 'mysql/%'
+ AND s.name NOT LIKE 'sys/%'
+ ORDER BY f.file_id;
+--enable_query_log
diff --git a/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result b/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result
index ae4e96dcd48..57edf7a187f 100644
--- a/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result
+++ b/mysql-test/suite/innodb/r/innodb-wl5522-debug-zip.result
@@ -1,6 +1,7 @@
call mtr.add_suppression("InnoDB: Tablespace for table .* is set as discarded.");
call mtr.add_suppression("InnoDB: Cannot calculate statistics for table .* because the .ibd file is missing. Please refer to .* for how to resolve the issue.");
call mtr.add_suppression("InnoDB: Error: Tablespace flags .* corrupted unused .*");
+call mtr.add_suppression("InnoDB: Tablespace flags: .* corrupted in file: .* ");
SET GLOBAL innodb_file_per_table = 1;
SELECT @@innodb_file_per_table;
@@innodb_file_per_table
diff --git a/mysql-test/suite/innodb/r/innodb_information_schema.result b/mysql-test/suite/innodb/r/innodb_information_schema.result
index 33dc50df745..15c3af325ad 100644
--- a/mysql-test/suite/innodb/r/innodb_information_schema.result
+++ b/mysql-test/suite/innodb/r/innodb_information_schema.result
@@ -7,10 +7,10 @@ X RECORD `test`.```t'\"_str` PRIMARY 4 '3', 'abc', '\\abc', 'abc\\', 'a\\bc', 'a
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_max` PRIMARY 2 127.000000, 140517642401116, 32767.000000, 140517642401147, 8388607.000000, 140517642401180, 2147483647.000000, 140517642401216, 9223372036854775808.000000, 140517642401261
-X RECORD `test`.`t_max` PRIMARY 2 127.000000, 140517642401116, 32767.000000, 140517642401147, 8388607.000000, 140517642401180, 2147483647.000000, 140517642401216, 9223372036854775808.000000, 140517642401261
-X RECORD `test`.`t_min` PRIMARY 2 18446744073709551616.000000, 140517642401133, 18446744073709518848.000000, 140517642401179, 18446744073701163008.000000, 140517642401225, 18446744071562067968.000000, 140517642401271, 9223372036854775808.000000, 140517642401316
-X RECORD `test`.`t_min` PRIMARY 2 18446744073709551616.000000, 140517642401133, 18446744073709518848.000000, 140517642401179, 18446744073701163008.000000, 140517642401225, 18446744071562067968.000000, 140517642401271, 9223372036854775808.000000, 140517642401316
+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(*)
diff --git a/mysql-test/suite/innodb/r/innodb_mysql.result b/mysql-test/suite/innodb/r/innodb_mysql.result
index 900e3814e49..a057719d18b 100644
--- a/mysql-test/suite/innodb/r/innodb_mysql.result
+++ b/mysql-test/suite/innodb/r/innodb_mysql.result
@@ -1,5 +1,9 @@
set global innodb_support_xa=default;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
set session innodb_support_xa=default;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SET SESSION DEFAULT_STORAGE_ENGINE = InnoDB;
drop table if exists t1,t2,t3,t1m,t1i,t2m,t2i,t4;
drop procedure if exists p1;
diff --git a/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test b/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test
index c61d10e8593..762b4758516 100644
--- a/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test
+++ b/mysql-test/suite/innodb/t/innodb-wl5522-debug-zip.test
@@ -20,6 +20,7 @@
call mtr.add_suppression("InnoDB: Tablespace for table .* is set as discarded.");
call mtr.add_suppression("InnoDB: Cannot calculate statistics for table .* because the .ibd file is missing. Please refer to .* for how to resolve the issue.");
call mtr.add_suppression("InnoDB: Error: Tablespace flags .* corrupted unused .*");
+call mtr.add_suppression("InnoDB: Tablespace flags: .* corrupted in file: .* ");
let MYSQLD_DATADIR =`SELECT @@datadir`;
let $innodb_file_per_table = `SELECT @@innodb_file_per_table`;
diff --git a/mysql-test/suite/innodb/t/innodb.test b/mysql-test/suite/innodb/t/innodb.test
index 79a00c27686..d129e866c8f 100644
--- a/mysql-test/suite/innodb/t/innodb.test
+++ b/mysql-test/suite/innodb/t/innodb.test
@@ -1141,7 +1141,7 @@ insert into t1 values
(244, 243), (245, 244), (246, 245), (247, 246),
(248, 247), (249, 248), (250, 249), (251, 250),
(252, 251), (253, 252), (254, 253), (255, 254);
---error 1296,1451
+--error 4029,1451
delete from t1 where id=0;
delete from t1 where id=255;
--error 0,1451
diff --git a/mysql-test/suite/innodb/t/innodb_mysql-master.opt b/mysql-test/suite/innodb/t/innodb_mysql-master.opt
index a177f285d66..a1ee2c096cf 100644
--- a/mysql-test/suite/innodb/t/innodb_mysql-master.opt
+++ b/mysql-test/suite/innodb/t/innodb_mysql-master.opt
@@ -1 +1,3 @@
---loose-innodb-lock-wait-timeout=2 --default-storage-engine=MyISAM
+--loose-innodb-lock-wait-timeout=2
+--default-storage-engine=MyISAM
+--loose-innodb-large-prefix=off
diff --git a/mysql-test/suite/innodb/t/innodb_simulate_comp_failures.test b/mysql-test/suite/innodb/t/innodb_simulate_comp_failures.test
index cf22935fad6..5a4978c9b37 100644
--- a/mysql-test/suite/innodb/t/innodb_simulate_comp_failures.test
+++ b/mysql-test/suite/innodb/t/innodb_simulate_comp_failures.test
@@ -1,6 +1,7 @@
--source include/big_test.inc
# test takes too long with valgrind
--source include/not_valgrind.inc
+--source include/have_debug.inc
--let $num_inserts = 1500
--let $num_ops = 3500
--source suite/innodb/include/innodb_simulate_comp_failures.inc
diff --git a/mysql-test/suite/innodb_zip/r/16k.result b/mysql-test/suite/innodb_zip/r/16k.result
index 3d9f39529e2..86049324811 100644
--- a/mysql-test/suite/innodb_zip/r/16k.result
+++ b/mysql-test/suite/innodb_zip/r/16k.result
@@ -8,7 +8,7 @@ variable_value
SELECT variable_value FROM information_schema.global_status
WHERE LOWER(variable_name) = 'innodb_buffer_pool_pages_total';
variable_value
-{checked_valid}
+512
# Test 3) Query some information_shema tables that are dependent upon
# the page size.
SELECT t.name table_name, t.n_cols, t.flag table_flags,
@@ -20,28 +20,8 @@ WHERE t.table_id = i.table_id
AND t.name LIKE 'mysql%'
ORDER BY t.name, i.index_id;
table_name n_cols table_flags index_name root_page type n_fields merge_threshold
-mysql/engine_cost 9 33 PRIMARY 3 3 3 50
-mysql/gtid_executed 6 33 PRIMARY 3 3 2 50
-mysql/help_category 7 33 PRIMARY 3 3 1 50
-mysql/help_category 7 33 name 4 2 1 50
-mysql/help_keyword 5 33 PRIMARY 3 3 1 50
-mysql/help_keyword 5 33 name 4 2 1 50
-mysql/help_relation 5 33 PRIMARY 3 3 2 50
-mysql/help_topic 9 33 PRIMARY 3 3 1 50
-mysql/help_topic 9 33 name 4 2 1 50
mysql/innodb_index_stats 11 33 PRIMARY 3 3 4 50
mysql/innodb_table_stats 9 33 PRIMARY 3 3 2 50
-mysql/plugin 5 33 PRIMARY 3 3 1 50
-mysql/servers 12 33 PRIMARY 3 3 1 50
-mysql/server_cost 7 33 PRIMARY 3 3 1 50
-mysql/slave_master_info 28 33 PRIMARY 3 3 1 50
-mysql/slave_relay_log_info 12 33 PRIMARY 3 3 1 50
-mysql/slave_worker_info 16 33 PRIMARY 3 3 2 50
-mysql/time_zone 5 33 PRIMARY 3 3 1 50
-mysql/time_zone_leap_second 5 33 PRIMARY 3 3 1 50
-mysql/time_zone_name 5 33 PRIMARY 3 3 1 50
-mysql/time_zone_transition 6 33 PRIMARY 3 3 2 50
-mysql/time_zone_transition_type 8 33 PRIMARY 3 3 2 50
CREATE TABLE t1 (a INT KEY, b TEXT) ROW_FORMAT=REDUNDANT ENGINE=innodb;
CREATE TABLE t2 (a INT KEY, b TEXT) ROW_FORMAT=COMPACT ENGINE=innodb;
CREATE TABLE t3 (a INT KEY, b TEXT) ROW_FORMAT=COMPRESSED ENGINE=innodb;
@@ -209,35 +189,35 @@ Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=16
+t1 Compressed row_format=COMPRESSED key_block_size=16
ALTER TABLE t1 KEY_BLOCK_SIZE=8;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=8
+t1 Compressed row_format=COMPRESSED key_block_size=8
ALTER TABLE t1 KEY_BLOCK_SIZE=4;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=4
+t1 Compressed row_format=COMPRESSED key_block_size=4
ALTER TABLE t1 KEY_BLOCK_SIZE=2;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=2
+t1 Compressed row_format=COMPRESSED key_block_size=2
ALTER TABLE t1 KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=1
+t1 Compressed row_format=COMPRESSED key_block_size=1
ALTER TABLE t1 KEY_BLOCK_SIZE=0;
SHOW WARNINGS;
Level Code Message
@@ -253,35 +233,35 @@ Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=16
+t1 Compressed row_format=COMPRESSED key_block_size=16
ALTER TABLE t1 KEY_BLOCK_SIZE=8;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=8
+t1 Compressed row_format=COMPRESSED key_block_size=8
ALTER TABLE t1 KEY_BLOCK_SIZE=4;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=4
+t1 Compressed row_format=COMPRESSED key_block_size=4
ALTER TABLE t1 KEY_BLOCK_SIZE=2;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=2
+t1 Compressed row_format=COMPRESSED key_block_size=2
ALTER TABLE t1 KEY_BLOCK_SIZE=1;
SHOW WARNINGS;
Level Code Message
SELECT table_name, row_format, create_options
FROM information_schema.tables WHERE table_name = 't1';
table_name row_format create_options
-t1 Compressed row_format=COMPRESSED KEY_BLOCK_SIZE=1
+t1 Compressed row_format=COMPRESSED key_block_size=1
ALTER TABLE t1 KEY_BLOCK_SIZE=0;
SHOW WARNINGS;
Level Code Message
@@ -298,33 +278,37 @@ SHOW VARIABLES LIKE 'innodb_file_per_table';
Variable_name Value
innodb_file_per_table OFF
CREATE TABLE t4 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=8;
-ERROR HY000: Table storage engine for 't4' doesn't have this option
+Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
-Error 1031 Table storage engine for 't4' doesn't have this option
+Error 1005 Can't create table `test`.`t4` (errno: 140 "Wrong create options")
+Warning 1030 Got error 140 "Wrong create options" from storage engine InnoDB
CREATE TABLE t5 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=16;
-ERROR HY000: Table storage engine for 't5' doesn't have this option
+Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
-Error 1031 Table storage engine for 't5' doesn't have this option
+Error 1005 Can't create table `test`.`t5` (errno: 140 "Wrong create options")
+Warning 1030 Got error 140 "Wrong create options" from storage engine InnoDB
SET GLOBAL innodb_file_per_table = ON;
SET GLOBAL innodb_file_format = `Antelope`;
Warnings:
Warning 131 Using innodb_file_format is deprecated and the parameter may be removed in future releases. See http://dev.mysql.com/doc/refman/5.7/en/innodb-file-format.html
CREATE TABLE t4 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=8;
-ERROR HY000: Table storage engine for 't4' doesn't have this option
+Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
-Error 1031 Table storage engine for 't4' doesn't have this option
+Error 1005 Can't create table `test`.`t4` (errno: 140 "Wrong create options")
+Warning 1030 Got error 140 "Wrong create options" from storage engine InnoDB
CREATE TABLE t5 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=16;
-ERROR HY000: Table storage engine for 't5' doesn't have this option
+Got one of the listed errors
SHOW WARNINGS;
Level Code Message
Warning 1478 InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
-Error 1031 Table storage engine for 't5' doesn't have this option
+Error 1005 Can't create table `test`.`t5` (errno: 140 "Wrong create options")
+Warning 1030 Got error 140 "Wrong create options" from storage engine InnoDB
SET GLOBAL innodb_file_format = `Barracuda`;
Warnings:
Warning 131 Using innodb_file_format is deprecated and the parameter may be removed in future releases. See http://dev.mysql.com/doc/refman/5.7/en/innodb-file-format.html
@@ -420,10 +404,8 @@ CHECK TABLE t1;
Table Op Msg_type Msg_text
test.t1 check status OK
EXPLAIN SELECT * FROM t1 WHERE b LIKE 'adfd%';
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL range b b 769 NULL 12 100.00 Using where
-Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b`,`test`.`t1`.`c` AS `c`,`test`.`t1`.`d` AS `d` from `test`.`t1` where (`test`.`t1`.`b` like 'adfd%')
+id select_type table type possible_keys key key_len ref rows Extra
+1 SIMPLE t1 ALL b NULL NULL NULL 15 Using where
DROP TABLE t1;
# Test 8) Test creating a table that could lead to undo log overflow.
CREATE TABLE t1(a blob,b blob,c blob,d blob,e blob,f blob,g blob,
@@ -489,27 +471,27 @@ CREATE INDEX t1st ON t1 (s(767), t(767));
SHOW CREATE TABLE t1;
Table Create Table
t1 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,
+ `a` blob DEFAULT NULL,
+ `b` blob DEFAULT NULL,
+ `c` blob DEFAULT NULL,
+ `d` blob DEFAULT NULL,
+ `e` blob DEFAULT NULL,
+ `f` blob DEFAULT NULL,
+ `g` blob DEFAULT NULL,
+ `h` blob DEFAULT NULL,
+ `i` blob DEFAULT NULL,
+ `j` blob DEFAULT NULL,
+ `k` blob DEFAULT NULL,
+ `l` blob DEFAULT NULL,
+ `m` blob DEFAULT NULL,
+ `n` blob DEFAULT NULL,
+ `o` blob DEFAULT NULL,
+ `p` blob DEFAULT NULL,
+ `q` blob DEFAULT NULL,
+ `r` blob DEFAULT NULL,
+ `s` blob DEFAULT NULL,
+ `t` blob DEFAULT NULL,
+ `u` blob DEFAULT NULL,
KEY `t1a` (`a`(767)),
KEY `t1b` (`b`(767)),
KEY `t1c` (`c`(767)),
@@ -620,22 +602,22 @@ CREATE INDEX ndx_p ON t12963823 (p(500));
SHOW CREATE TABLE t12963823;
Table Create Table
t12963823 CREATE TABLE `t12963823` (
- `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,
+ `a` blob DEFAULT NULL,
+ `b` blob DEFAULT NULL,
+ `c` blob DEFAULT NULL,
+ `d` blob DEFAULT NULL,
+ `e` blob DEFAULT NULL,
+ `f` blob DEFAULT NULL,
+ `g` blob DEFAULT NULL,
+ `h` blob DEFAULT NULL,
+ `i` blob DEFAULT NULL,
+ `j` blob DEFAULT NULL,
+ `k` blob DEFAULT NULL,
+ `l` blob DEFAULT NULL,
+ `m` blob DEFAULT NULL,
+ `n` blob DEFAULT NULL,
+ `o` blob DEFAULT NULL,
+ `p` blob DEFAULT NULL,
KEY `ndx_c` (`c`(500)),
KEY `ndx_d` (`d`(500)),
KEY `ndx_e` (`e`(500)),
@@ -727,11 +709,9 @@ EXPLAIN
SELECT COUNT(*) FROM
(SELECT * FROM t1 FORCE INDEX (idx,PRIMARY)
WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 PRIMARY <derived2> NULL ALL NULL NULL NULL NULL 1537 100.00 NULL
-2 DERIVED t1 NULL index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 1537 100.00 Using sort_union(idx,PRIMARY); Using where
-Warnings:
-Note 1003 /* select#1 */ select count(0) AS `COUNT(*)` from (/* select#2 */ select `test`.`t1`.`pk` AS `pk`,`test`.`t1`.`a` AS `a`,`test`.`t1`.`b` AS `b` from `test`.`t1` FORCE INDEX (PRIMARY) FORCE INDEX (`idx`) where ((`test`.`t1`.`a` between 2 and 7) or (`test`.`t1`.`pk` = 1000000))) `t`
+id select_type table type possible_keys key key_len ref rows Extra
+1 PRIMARY <derived2> ALL NULL NULL NULL NULL 1537
+2 DERIVED t1 index_merge PRIMARY,idx idx,PRIMARY 5,4 NULL 1537 Using sort_union(idx,PRIMARY); Using where
SELECT COUNT(*) FROM
(SELECT * FROM t1 FORCE INDEX (idx,PRIMARY)
WHERE a BETWEEN 2 AND 7 OR pk=1000000) AS t;
diff --git a/mysql-test/suite/innodb_zip/r/wl6347_comp_indx_stat.result b/mysql-test/suite/innodb_zip/r/wl6347_comp_indx_stat.result
index 3b98527250b..509ffe91de5 100644
--- a/mysql-test/suite/innodb_zip/r/wl6347_comp_indx_stat.result
+++ b/mysql-test/suite/innodb_zip/r/wl6347_comp_indx_stat.result
@@ -320,7 +320,6 @@ AND table_name='tab5' AND database_name='test'
AND index_name like 'idx%' ;
compress_stat 1
The size of the tab5.ibd file: 5242880
-# restart
# set the flag on (default off)
SET GLOBAL innodb_cmp_per_index_enabled=ON;
# set the flags
@@ -666,7 +665,6 @@ AND table_name='tab5' AND database_name='test'
AND index_name like 'idx%' ;
compress_stat 1
The size of the tab5.ibd file: 2097152
-# restart
# set the flag on (default off)
SET GLOBAL innodb_cmp_per_index_enabled=ON;
# set the flags
@@ -1964,7 +1962,6 @@ AND table_name='tab5' AND database_name='test'
AND index_name like 'idx%' ;
compress_stat 1
The size of the tab5.ibd file: 65536
-# restart
# set the flag on (default off)
SET GLOBAL innodb_cmp_per_index_enabled=ON;
# set the flags
@@ -2312,7 +2309,6 @@ AND table_name='tab5' AND database_name='test'
AND index_name like 'idx%' ;
compress_stat 1
The size of the tab5.ibd file: 65536
-# restart
# set the flag on (default off)
SET GLOBAL innodb_cmp_per_index_enabled=ON;
# set the flags
@@ -5113,7 +5109,6 @@ AND table_name='tab5' AND database_name='test'
AND index_name like 'idx%' ;
compress_stat 1
The size of the tab5.ibd file: 65536
-# restart
# set the flag on (default off)
SET GLOBAL innodb_cmp_per_index_enabled=ON;
# set the flags
@@ -6734,7 +6729,6 @@ AND table_name='tab5' AND database_name='test'
AND index_name like 'idx%' ;
compress_stat 1
The size of the tab5.ibd file: 65536
-# restart
# set the flag on (default off)
SET GLOBAL innodb_cmp_per_index_enabled=ON;
# set the flags
diff --git a/mysql-test/suite/innodb_zip/r/wl6560.result b/mysql-test/suite/innodb_zip/r/wl6560.result
deleted file mode 100644
index bf46d8a41a0..00000000000
--- a/mysql-test/suite/innodb_zip/r/wl6560.result
+++ /dev/null
@@ -1,418 +0,0 @@
-set global innodb_file_per_table = off;
-# files in MYSQL_DATA_DIR
-ibtmp1
-select @@global.innodb_file_per_table;
-@@global.innodb_file_per_table
-0
-create temporary table t1 (i int, f float, c char(100)) engine=innodb;
-insert into t1 values (100, 1.1, 'pune');
-insert into t1 values (99, 1.2, 'mumbai');
-insert into t1 values (98, 1.3, 'jaipur');
-insert into t1 values (97, 1.4, 'delhi');
-insert into t1 values (96, 1.5, 'ahmedabad');
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-select * from t1 where i = 98;
-i f c
-98 1.3 jaipur
-select * from t1 where i < 100;
-i f c
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-explain select * from t1 where f > 1.29999;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 5 33.33 Using where
-Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`i` AS `i`,`test`.`t1`.`f` AS `f`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (`test`.`t1`.`f` > 1.29999)
-alter table t1 add index sec_index(f);
-explain select * from t1 where f > 1.29999;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL ALL sec_index NULL NULL NULL 5 60.00 Using where
-Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`i` AS `i`,`test`.`t1`.`f` AS `f`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (`test`.`t1`.`f` > 1.29999)
-select * from t1 where f > 1.29999;
-i f c
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-explain select * from t1 where i = 100;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 5 20.00 Using where
-Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`i` AS `i`,`test`.`t1`.`f` AS `f`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (`test`.`t1`.`i` = 100)
-alter table t1 add unique index pri_index(i);
-explain select * from t1 where i = 100;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL const pri_index pri_index 5 const 1 100.00 NULL
-Warnings:
-Note 1003 /* select#1 */ select '100' AS `i`,'1.1' AS `f`,'pune' AS `c` from `test`.`t1` where 1
-select * from t1 where i = 100;
-i f c
-100 1.1 pune
-delete from t1 where i < 97;
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-insert into t1 values (96, 1.5, 'kolkata');
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 kolkata
-update t1 set f = 1.44 where c = 'delhi';
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.44 delhi
-96 1.5 kolkata
-truncate table t1;
-insert into t1 values (100, 1.1, 'pune');
-insert into t1 values (99, 1.2, 'mumbai');
-insert into t1 values (98, 1.3, 'jaipur');
-insert into t1 values (97, 1.4, 'delhi');
-insert into t1 values (96, 1.5, 'ahmedabad');
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-alter table t1 discard tablespace;
-ERROR HY000: Cannot DISCARD/IMPORT tablespace associated with temporary table
-alter table t1 import tablespace;
-ERROR HY000: Cannot DISCARD/IMPORT tablespace associated with temporary table
-drop table t1;
-#files in MYSQL_TMP_DIR
-set global innodb_file_per_table = 1;
-select @@global.innodb_file_per_table;
-@@global.innodb_file_per_table
-1
-create temporary table t1
-(i int, f float, c char(100)) engine = innodb key_block_size = 4;
-show create table t1;
-Table Create Table
-t1 CREATE TEMPORARY TABLE `t1` (
- `i` int(11) DEFAULT NULL,
- `f` float DEFAULT NULL,
- `c` char(100) DEFAULT NULL
-) ENGINE=InnoDB DEFAULT CHARSET=latin1 KEY_BLOCK_SIZE=4
-#files in MYSQL_TMP_DIR
-#sql<temporary>.ibd
-insert into t1 values (100, 1.1, 'pune');
-insert into t1 values (99, 1.2, 'mumbai');
-insert into t1 values (98, 1.3, 'jaipur');
-insert into t1 values (97, 1.4, 'delhi');
-insert into t1 values (96, 1.5, 'ahmedabad');
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-select * from t1 where i = 98;
-i f c
-98 1.3 jaipur
-select * from t1 where i < 100;
-i f c
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-explain select * from t1 where f > 1.29999;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 5 33.33 Using where
-Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`i` AS `i`,`test`.`t1`.`f` AS `f`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (`test`.`t1`.`f` > 1.29999)
-alter table t1 add index sec_index(f);
-explain select * from t1 where f > 1.29999;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL ALL sec_index NULL NULL NULL 5 60.00 Using where
-Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`i` AS `i`,`test`.`t1`.`f` AS `f`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (`test`.`t1`.`f` > 1.29999)
-select * from t1 where f > 1.29999;
-i f c
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-explain select * from t1 where i = 100;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL ALL NULL NULL NULL NULL 5 20.00 Using where
-Warnings:
-Note 1003 /* select#1 */ select `test`.`t1`.`i` AS `i`,`test`.`t1`.`f` AS `f`,`test`.`t1`.`c` AS `c` from `test`.`t1` where (`test`.`t1`.`i` = 100)
-alter table t1 add unique index pri_index(i);
-explain select * from t1 where i = 100;
-id select_type table partitions type possible_keys key key_len ref rows filtered Extra
-1 SIMPLE t1 NULL const pri_index pri_index 5 const 1 100.00 NULL
-Warnings:
-Note 1003 /* select#1 */ select '100' AS `i`,'1.1' AS `f`,'pune' AS `c` from `test`.`t1` where 1
-select * from t1 where i = 100;
-i f c
-100 1.1 pune
-delete from t1 where i < 97;
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-insert into t1 values (96, 1.5, 'kolkata');
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 kolkata
-update t1 set f = 1.44 where c = 'delhi';
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.44 delhi
-96 1.5 kolkata
-truncate table t1;
-insert into t1 values (100, 1.1, 'pune');
-insert into t1 values (99, 1.2, 'mumbai');
-insert into t1 values (98, 1.3, 'jaipur');
-insert into t1 values (97, 1.4, 'delhi');
-insert into t1 values (96, 1.5, 'ahmedabad');
-select * from t1;
-i f c
-100 1.1 pune
-99 1.2 mumbai
-98 1.3 jaipur
-97 1.4 delhi
-96 1.5 ahmedabad
-alter table t1 discard tablespace;
-ERROR HY000: Cannot DISCARD/IMPORT tablespace associated with temporary table
-drop table t1;
-set global innodb_file_per_table = off;
-create temporary table t1
-(keyc int, c1 char(100), c2 char(100),
-primary key(keyc)) engine = innodb;
-CREATE PROCEDURE populate_t1()
-BEGIN
-DECLARE i INT DEFAULT 1;
-while (i <= 20000) DO
-insert into t1 values (i, 'a', 'b');
-SET i = i + 1;
-END WHILE;
-END|
-set autocommit=0;
-select count(*) from t1;
-count(*)
-0
-call populate_t1();
-select count(*) from t1;
-count(*)
-20000
-select * from t1 limit 10;
-keyc c1 c2
-1 a b
-2 a b
-3 a b
-4 a b
-5 a b
-6 a b
-7 a b
-8 a b
-9 a b
-10 a b
-set autocommit=1;
-truncate table t1;
-select count(*) from t1;
-count(*)
-0
-drop procedure populate_t1;
-drop table t1;
-create temporary table t1 (keyc int, c1 char(100), c2 char(100)) engine = innodb;
-insert into t1 values (1, 'c', 'b');
-select * from t1;
-keyc c1 c2
-1 c b
-# restart
-# files in MYSQL_DATA_DIR
-ibtmp1
-use test;
-select * from t1;
-ERROR 42S02: Table 'test.t1' doesn't exist
-"testing temp-table creation in --innodb_read_only mode"
-# restart: --innodb-read-only
-use test;
-show tables;
-Tables_in_test
-create temporary table t1 (keyc int, c1 char(100), c2 char(100)) engine = innodb;
-ERROR HY000: InnoDB is in read only mode.
-"testing system and temp tablespace name conflict"
-"restarting server in normal mode"
-# restart
-show tables;
-Tables_in_test
-create temporary table t1 (keyc int, c1 char(100), c2 char(100)) engine = innodb;
-drop table t1;
-# test condition of full-temp-tablespace
-# restart: --innodb_temp_data_file_path=ibtmp1:12M
-create temporary table t1
-(keyc int, c1 char(100), c2 char(100),
-primary key(keyc)) engine = innodb;
-CREATE PROCEDURE populate_t1()
-BEGIN
-DECLARE i INT DEFAULT 1;
-while (i <= 20000) DO
-insert into t1 values (i, 'a', 'b');
-SET i = i + 1;
-END WHILE;
-END|
-set autocommit=0;
-select count(*) from t1;
-count(*)
-0
-call populate_t1();
-ERROR HY000: The table 't1' is full
-drop procedure populate_t1;
-drop table t1;
-set innodb_strict_mode = off;
-set global innodb_file_per_table = 0;
-set global innodb_file_format = 'Antelope';
-create temporary table t (
-i int)
-engine = innodb row_format = compressed;
-show warnings;
-Level Code Message
-Warning NUMBER InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
-Warning NUMBER InnoDB: assuming ROW_FORMAT=DYNAMIC.
-drop table t;
-create temporary table t (
-i int)
-engine = innodb row_format = compressed key_block_size = 8;
-show warnings;
-Level Code Message
-Warning NUMBER InnoDB: KEY_BLOCK_SIZE requires innodb_file_per_table.
-Warning NUMBER InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
-Warning NUMBER InnoDB: ignoring KEY_BLOCK_SIZE=NUMBER.
-Warning NUMBER InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_per_table.
-Warning NUMBER InnoDB: assuming ROW_FORMAT=DYNAMIC.
-drop table t;
-set global innodb_file_per_table = 1;
-create temporary table t (
-i int)
-engine = innodb row_format = compressed key_block_size = 8;
-show warnings;
-Level Code Message
-Warning NUMBER InnoDB: KEY_BLOCK_SIZE requires innodb_file_format > Antelope.
-Warning NUMBER InnoDB: ignoring KEY_BLOCK_SIZE=NUMBER.
-Warning NUMBER InnoDB: ROW_FORMAT=COMPRESSED requires innodb_file_format > Antelope.
-Warning NUMBER InnoDB: assuming ROW_FORMAT=DYNAMIC.
-drop table t;
-create temporary table t (
-i int)
-engine = innodb row_format = dynamic;
-show warnings;
-Level Code Message
-#files in MYSQL_TMP_DIR
-drop table t;
-set innodb_strict_mode = on;
-create temporary table t (
-i int)
-engine = innodb row_format = dynamic;
-drop table t;
-set global innodb_file_format = 'Barracuda';
-set innodb_strict_mode = off;
-create temporary table t (
-i int)
-engine = innodb row_format = compressed key_block_size = 8;
-set innodb_strict_mode = default;
-#files in MYSQL_TMP_DIR
-#sql<temporary>.ibd
-drop table t;
-create temporary table t (
-i int)
-engine = innodb row_format = compressed;
-show warnings;
-Level Code Message
-#files in MYSQL_TMP_DIR
-#sql<temporary>.ibd
-drop table t;
-create temporary table t (
-i int)
-engine = innodb row_format = dynamic;
-show warnings;
-Level Code Message
-#files in MYSQL_TMP_DIR
-drop table t;
-set innodb_strict_mode = on;
-create temporary table t (
-i int)
-engine = innodb row_format = dynamic;
-show warnings;
-Level Code Message
-drop table t;
-set innodb_strict_mode = off;
-#files in MYSQL_TMP_DIR
-create temporary table t (
-i int)
-engine = innodb row_format = dynamic key_block_size = 4;
-show warnings;
-Level Code Message
-Warning NUMBER InnoDB: ignoring KEY_BLOCK_SIZE=NUMBER unless ROW_FORMAT=COMPRESSED.
-#files in MYSQL_TMP_DIR
-#sql<temporary>.ibd
-drop table t;
-create temporary table t (
-i int)
-engine = innodb row_format = compact;
-show warnings;
-Level Code Message
-#files in MYSQL_TMP_DIR
-drop table t;
-create temporary table t (
-i int)
-engine = innodb key_block_size = 4;
-show warnings;
-Level Code Message
-#files in MYSQL_TMP_DIR
-#sql<temporary>.ibd
-drop table t;
-"testing temp tablespace non-support for raw device"
-"testing temp tablespace non-support for raw device"
-# restart
-show tables;
-Tables_in_test
-create temporary table t1 (
-keyc int, c1 char(100), c2 char(100)
-) engine = innodb;
-drop table t1;
-"try starting server with temp-tablespace size < min. threshold"
-"try starting server with sys-tablespace size < min. threshold"
-# restart
-show tables;
-Tables_in_test
-create temporary table t1 (
-keyc int, c1 char(100), c2 char(100)
-) engine = innodb;
-drop table t1;
-"try starting server with no file specified for temp-tablespace"
-# restart
-show tables;
-Tables_in_test
-create temporary table t1 (
-keyc int, c1 char(100), c2 char(100)
-) engine = innodb;
-drop table t1;
diff --git a/mysql-test/suite/innodb_zip/r/wl6915_1.result b/mysql-test/suite/innodb_zip/r/wl6915_1.result
index 0ffc2f43265..bba81098e9d 100644
--- a/mysql-test/suite/innodb_zip/r/wl6915_1.result
+++ b/mysql-test/suite/innodb_zip/r/wl6915_1.result
@@ -270,9 +270,14 @@ rollback;
set n = n - 1;
end while;
end|
+connect con1,localhost,root,,;
+connect con2,localhost,root,,;
#---client 1 : dml operation ---"
+connection con1;
#---client 2 : dml operation ---"
+connection con2;
# In connection 1
+connection con1;
SELECT count(*) FROM t1_1;
count(*)
36
@@ -550,6 +555,7 @@ c1
138
140
# In connection 2
+connection con2;
SELECT count(*) FROM t1_2;
count(*)
36
@@ -827,6 +833,7 @@ c1
138
140
# In connection 1
+connection con1;
set AUTOCOMMIT = 0;
ALTER TABLE t1_temp DROP PRIMARY KEY;
ALTER TABLE t1_temp ADD PRIMARY KEY (c1);
@@ -898,17 +905,9 @@ SELECT c1,c2,c3,c4,c5,c6,c7,c9 FROM t4_temp WHERE c1 = 20;
c1 c2 c3 c4 c5 c6 c7 c9
20 1 a a a a a 100.550
update ignore t1_temp set c1 = 20 WHERE c1 = 140 ;
-Warnings:
-Warning 1062 Duplicate entry '20' for key 'PRIMARY'
update ignore t2_temp set c1 = 20 WHERE c1 = 140 ;
-Warnings:
-Warning 1062 Duplicate entry '20' for key 'PRIMARY'
update ignore t3_temp set c1 = 20 WHERE c1 = 140 ;
-Warnings:
-Warning 1062 Duplicate entry '20' for key 'PRIMARY'
update ignore t4_temp set c1 = 20 WHERE c1 = 140 ;
-Warnings:
-Warning 1062 Duplicate entry '20' for key 'PRIMARY'
SELECT count(*) FROM t1_temp WHERE c1 = 140;
count(*)
1
@@ -938,11 +937,19 @@ SELECT c1,c2,c3,c4,c5,c6,c7,c9,c10,c11 FROM t1_temp WHERE c1 < 0;
c1 c2 c3 c4 c5 c6 c7 c9 c10 c11
-2 -2 a a a a a 100.550 99 test
DROP TABLE t1_1 ,t2_1 ,t3_1,t4_1;
+disconnect con1;
+connection con2;
DROP TABLE t1_2 ,t2_2 ,t3_2,t4_2;
-# restart: --innodb_undo_tablespaces=0 --innodb_rollback_segments=20 --innodb_undo_logs=20 --innodb_log_files_in_group=4
+disconnect con2;
+connection default;
+connect con1,localhost,root,,;
+connect con2,localhost,root,,;
+connection con1;
call populate_tables('_1');;
+connection con2;
call populate_tables('_2');;
"#connection 1 - verify tables"
+connection con1;
SELECT count(*) FROM t1_1;
count(*)
36
@@ -1220,7 +1227,9 @@ c1
138
140
DROP TABLE t1_1 ,t2_1 ,t3_1,t4_1;
+disconnect con1;
"#connection 2 - verify tables"
+connection con2;
SELECT count(*) FROM t1_2;
count(*)
36
@@ -1498,10 +1507,16 @@ c1
138
140
DROP TABLE t1_2 ,t2_2 ,t3_2,t4_2;
-# restart: --innodb_undo_tablespaces=0 --innodb_rollback_segments=30 --innodb_undo_logs=20 --innodb_log_files_in_group=4
+disconnect con2;
+connection default;
+connect con1,localhost,root,,;
+connect con2,localhost,root,,;
+connection con1;
call populate_tables('_1');;
+connection con2;
call populate_tables('_2');;
"#connection 1 - verify tables"
+connection con1;
SELECT count(*) FROM t1_1;
count(*)
36
@@ -1779,7 +1794,9 @@ c1
138
140
DROP TABLE t1_1 ,t2_1 ,t3_1,t4_1;
+disconnect con1;
"#connection 2 - verify tables"
+connection con2;
SELECT count(*) FROM t1_2;
count(*)
36
@@ -2057,4 +2074,6 @@ c1
138
140
DROP TABLE t1_2 ,t2_2 ,t3_2,t4_2;
+disconnect con2;
+connection default;
DROP PROCEDURE populate_tables;
diff --git a/mysql-test/suite/innodb_zip/t/16k-master.opt b/mysql-test/suite/innodb_zip/t/16k-master.opt
new file mode 100644
index 00000000000..82f574a8039
--- /dev/null
+++ b/mysql-test/suite/innodb_zip/t/16k-master.opt
@@ -0,0 +1,3 @@
+--loose-innodb-sys-indexes
+--loose-innodb-sys-tablespaces
+--loose-innodb-sys-datafiles
diff --git a/mysql-test/suite/innodb_zip/t/16k.test b/mysql-test/suite/innodb_zip/t/16k.test
index 274b0b8e1bb..2885d1329ad 100644
--- a/mysql-test/suite/innodb_zip/t/16k.test
+++ b/mysql-test/suite/innodb_zip/t/16k.test
@@ -288,18 +288,18 @@ DROP TABLE t1;
SET SESSION innodb_strict_mode = ON;
SET GLOBAL innodb_file_per_table = OFF;
SHOW VARIABLES LIKE 'innodb_file_per_table';
---error ER_ILLEGAL_HA
+--error ER_ILLEGAL_HA,1005
CREATE TABLE t4 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=8;
SHOW WARNINGS;
---error ER_ILLEGAL_HA
+--error ER_ILLEGAL_HA,1005
CREATE TABLE t5 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=16;
SHOW WARNINGS;
SET GLOBAL innodb_file_per_table = ON;
SET GLOBAL innodb_file_format = `Antelope`;
---error ER_ILLEGAL_HA
+--error ER_ILLEGAL_HA,1005
CREATE TABLE t4 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=8;
SHOW WARNINGS;
---error ER_ILLEGAL_HA
+--error ER_ILLEGAL_HA,1005
CREATE TABLE t5 (id int PRIMARY KEY) ENGINE=innodb KEY_BLOCK_SIZE=16;
SHOW WARNINGS;
SET GLOBAL innodb_file_format = `Barracuda`;
diff --git a/mysql-test/suite/innodb_zip/t/disabled.def b/mysql-test/suite/innodb_zip/t/disabled.def
index d3799d0e2c9..2808bc556a7 100644
--- a/mysql-test/suite/innodb_zip/t/disabled.def
+++ b/mysql-test/suite/innodb_zip/t/disabled.def
@@ -14,4 +14,4 @@ restart : Not supported by MariaDB 10.2 2/9/2016 jplindst
innochecksum : MDEV-10727 2/9/2016 jplindst
innochecksum_2 : MDEV-10727 2/9/2016 jplindst
innochecksum_3 : MDEV-10727 2/9/2016 jplindst
-
+wl6560 : MDEV_10727
diff --git a/mysql-test/suite/innodb_zip/t/large_blob.test b/mysql-test/suite/innodb_zip/t/large_blob.test
index dc1dc2eba29..b9888ccb53c 100644
--- a/mysql-test/suite/innodb_zip/t/large_blob.test
+++ b/mysql-test/suite/innodb_zip/t/large_blob.test
@@ -3,7 +3,7 @@
--echo #
--source include/have_innodb.inc
---source include/have_nodebug.inc
+--source include/not_debug.inc
--source include/big_test.inc
--disable_query_log
diff --git a/mysql-test/suite/innodb_zip/t/wl6560.test b/mysql-test/suite/innodb_zip/t/wl6560.test
index 041dd453c72..55d36747938 100644
--- a/mysql-test/suite/innodb_zip/t/wl6560.test
+++ b/mysql-test/suite/innodb_zip/t/wl6560.test
@@ -164,12 +164,12 @@ select * from t1;
#
#
--echo "testing temp-table creation in --innodb_read_only mode"
-let $restart_parameters = restart: --innodb-read-only;
+let $restart_parameters=--innodb-read-only;
--source include/restart_mysqld.inc
#
use test;
show tables;
---error ER_INNODB_READ_ONLY
+--error ER_INNODB_READ_ONLY, 1005
create temporary table t1 (keyc int, c1 char(100), c2 char(100)) engine = innodb;
#-----------------------------------------------------------------------------
@@ -198,7 +198,7 @@ drop table t1;
# and insert enough data to make it full.
#
--echo # test condition of full-temp-tablespace
-let $restart_parameters = restart: --innodb_temp_data_file_path=ibtmp1:12M;
+let $restart_parameters=--innodb_temp_data_file_path=ibtmp1:12M;
--source include/restart_mysqld.inc
#
create temporary table t1
@@ -366,7 +366,6 @@ let SEARCH_PATTERN = support raw device;
--source include/search_pattern_in_file.inc
--remove_file $SEARCH_FILE
-let $restart_parameters = restart;
--source include/start_mysqld.inc
show tables;
diff --git a/mysql-test/suite/innodb_zip/t/wl6915_1.test b/mysql-test/suite/innodb_zip/t/wl6915_1.test
index 625c8a36db2..7f0f734d16a 100644
--- a/mysql-test/suite/innodb_zip/t/wl6915_1.test
+++ b/mysql-test/suite/innodb_zip/t/wl6915_1.test
@@ -517,7 +517,7 @@ connection default;
#
## trying with VALUES innodb_undo_tablespaces, innodb_undo_logs ,innodb_log_files_in_group
##
-let $restart_parameters = restart: --innodb_undo_tablespaces=0 --innodb_rollback_segments=20 --innodb_undo_logs=20 --innodb_log_files_in_group=4;
+let $restart_parameters=--innodb_undo_tablespaces=0 --innodb_rollback_segments=20 --innodb_undo_logs=20 --innodb_log_files_in_group=4;
--source include/restart_mysqld.inc
# Create two client for concurrent execution
@@ -574,7 +574,7 @@ disconnect con2;
connection default;
# innodb_undo_logs > non redo rsegment
-let $restart_parameters = restart: --innodb_undo_tablespaces=0 --innodb_rollback_segments=30 --innodb_undo_logs=20 --innodb_log_files_in_group=4;
+let $restart_parameters=--innodb_undo_tablespaces=0 --innodb_rollback_segments=30 --innodb_undo_logs=20 --innodb_log_files_in_group=4;
--source include/restart_mysqld.inc
connect (con1,localhost,root,,);
diff --git a/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result b/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result
index 754b09310bf..8384ee3d361 100644
--- a/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result
+++ b/mysql-test/suite/sys_vars/r/innodb_support_xa_basic.result
@@ -8,17 +8,27 @@ SELECT @global_start_value;
1
'#--------------------FN_DYNVARS_046_01------------------------#'
SET @@session.innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SET @@session.innodb_support_xa = DEFAULT;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
1
SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SET @@global.innodb_support_xa = DEFAULT;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
1
'#---------------------FN_DYNVARS_046_02-------------------------#'
SET innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@innodb_support_xa;
@@innodb_support_xa
1
@@ -29,27 +39,39 @@ ERROR 42S02: Unknown table 'local' in field list
SELECT global.innodb_support_xa;
ERROR 42S02: Unknown table 'global' in field list
SET session innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
-0
+1
SET global innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
-0
+1
'#--------------------FN_DYNVARS_046_03------------------------#'
SET @@session.innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
-0
+1
SET @@session.innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
1
SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
-0
+1
SET @@global.innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
1
@@ -67,9 +89,11 @@ ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TRÜE'
SET @@session.innodb_support_xa = ÕN;
ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN'
SET @@session.innodb_support_xa = OF;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
-0
+1
SET @@session.innodb_support_xa = ÓFF;
ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF'
SET @@global.innodb_support_xa = -1;
@@ -88,18 +112,26 @@ ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'TRÜE'
SET @@global.innodb_support_xa = ÕN;
ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÕN'
SET @@global.innodb_support_xa = OF;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
-0
+1
SET @@global.innodb_support_xa = ÓFF;
ERROR 42000: Variable 'innodb_support_xa' can't be set to the value of 'ÓFF'
'#-------------------FN_DYNVARS_046_05----------------------------#'
SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SET @@session.innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@global.innodb_support_xa AS res_is_0;
res_is_0
-0
+1
SET @@global.innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@session.innodb_support_xa AS res_is_1;
res_is_1
1
@@ -112,11 +144,11 @@ VARIABLE_VALUE
1
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
-0
+1
SELECT VARIABLE_VALUE FROM INFORMATION_SCHEMA.GLOBAL_VARIABLES
WHERE VARIABLE_NAME='innodb_support_xa';
VARIABLE_VALUE
-OFF
+ON
'#----------------------FN_DYNVARS_046_07------------------------#'
SELECT IF(@@session.innodb_support_xa, "ON", "OFF") =
VARIABLE_VALUE FROM INFORMATION_SCHEMA.SESSION_VARIABLES
@@ -133,43 +165,63 @@ VARIABLE_VALUE
ON
'#---------------------FN_DYNVARS_046_08-------------------------#'
SET @@session.innodb_support_xa = OFF;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
-0
+1
SET @@session.innodb_support_xa = ON;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
1
SET @@global.innodb_support_xa = OFF;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
-0
+1
SET @@global.innodb_support_xa = ON;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
1
'#---------------------FN_DYNVARS_046_09----------------------#'
SET @@session.innodb_support_xa = TRUE;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
1
SET @@session.innodb_support_xa = FALSE;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
-0
+1
SET @@global.innodb_support_xa = TRUE;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
1
SET @@global.innodb_support_xa = FALSE;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
-0
+1
SET @@session.innodb_support_xa = @session_start_value;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
1
SET @@global.innodb_support_xa = @global_start_value;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
1
diff --git a/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result b/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result
index 7291b60ea62..d86cf896016 100644
--- a/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result
+++ b/mysql-test/suite/sys_vars/r/innodb_support_xa_func.result
@@ -1,21 +1,27 @@
'#--------------------FN_DYNVARS_046_01-------------------------#'
SET @@global.innodb_support_xa = OFF;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
connect con1,localhost,root,,,,;
connection con1;
SELECT @@global.innodb_support_xa;
@@global.innodb_support_xa
-0
+1
SELECT @@session.innodb_support_xa;
@@session.innodb_support_xa
-0
+1
disconnect con1;
'#--------------------FN_DYNVARS_046_01-------------------------#'
connection default;
SET @@global.innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
drop table if exists t1, t2;
create table t1 (a int) engine=innodb;
'---check when innodb_support_xa is 1---'
SET @@innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
xa start 'test1';
INSERT t1 values (10);
xa end 'test1';
@@ -25,6 +31,8 @@ SELECT * from t1;
a
'---check when innodb_support_xa is 0---'
SET @@innodb_support_xa = 0;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases. Only innodb_support_xa=ON is allowed.
xa start 'test1';
INSERT t1 values (10);
xa end 'test1';
@@ -34,7 +42,11 @@ SELECT * from t1;
a
'------general xa testing--------'
SET @@global.innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
SET @@innodb_support_xa = 1;
+Warnings:
+Warning 131 Using innodb_support_xa is deprecated and the parameter may be removed in future releases.
xa start 'testa','testb';
INSERT t1 values (30);
COMMIT;
diff --git a/mysql-test/t/partition_innodb_plugin.test b/mysql-test/t/partition_innodb_plugin.test
index 3a3ae257beb..a514736ff42 100644
--- a/mysql-test/t/partition_innodb_plugin.test
+++ b/mysql-test/t/partition_innodb_plugin.test
@@ -3,6 +3,8 @@
let $MYSQLD_DATADIR= `SELECT @@datadir`;
+call mtr.add_suppression("InnoDB: Table .* does not exist in the InnoDB internal data dictionary .*");
+
--echo #
--echo # Bug#11766879/Bug#60106: DIFF BETWEEN # OF INDEXES IN MYSQL VS INNODB,
--echo # PARTITONING, ON INDEX CREATE
diff --git a/mysql-test/t/row-checksum.opt b/mysql-test/t/row-checksum.opt
new file mode 100644
index 00000000000..977b569a781
--- /dev/null
+++ b/mysql-test/t/row-checksum.opt
@@ -0,0 +1 @@
+--loose-innodb-strict-mode=off
diff --git a/sql/handler.cc b/sql/handler.cc
index 3fbd1b3a71a..6e9d8dcb4d2 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -359,7 +359,7 @@ int ha_init_errors(void)
SETMSG(HA_ERR_NO_CONNECTION, "Could not connect to storage engine");
SETMSG(HA_ERR_TABLE_DEF_CHANGED, ER_DEFAULT(ER_TABLE_DEF_CHANGED));
SETMSG(HA_ERR_FOREIGN_DUPLICATE_KEY, "FK constraint would lead to duplicate key");
- SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, "Table upgrade required. Please do \"REPAIR TABLE %`\" or dump/reload to fix it");
+ SETMSG(HA_ERR_TABLE_NEEDS_UPGRADE, ER_DEFAULT(ER_TABLE_NEEDS_UPGRADE));
SETMSG(HA_ERR_TABLE_READONLY, ER_DEFAULT(ER_OPEN_AS_READONLY));
SETMSG(HA_ERR_AUTOINC_READ_FAILED, ER_DEFAULT(ER_AUTOINC_READ_FAILED));
SETMSG(HA_ERR_AUTOINC_ERANGE, ER_DEFAULT(ER_WARN_DATA_OUT_OF_RANGE));
@@ -370,6 +370,17 @@ int ha_init_errors(void)
SETMSG(HA_ERR_TABLE_IN_FK_CHECK, ER_DEFAULT(ER_TABLE_IN_FK_CHECK));
SETMSG(HA_ERR_DISK_FULL, ER_DEFAULT(ER_DISK_FULL));
SETMSG(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE, "Too many words in a FTS phrase or proximity search");
+ SETMSG(HA_ERR_FK_DEPTH_EXCEEDED, ER_DEFAULT(ER_FK_DEPTH_EXCEEDED));
+ SETMSG(HA_MISSING_CREATE_OPTION, ER_DEFAULT(ER_MISSING_HA_CREATE_OPTION));
+ SETMSG(HA_ERR_SE_OUT_OF_MEMORY, ER_DEFAULT(ER_ENGINE_OUT_OF_MEMORY));
+ SETMSG(HA_ERR_TABLE_CORRUPT, ER_DEFAULT(ER_TABLE_CORRUPT));
+ SETMSG(HA_ERR_QUERY_INTERRUPTED, ER_DEFAULT(ER_QUERY_INTERRUPTED));
+ SETMSG(HA_ERR_TABLESPACE_MISSING, ER_DEFAULT(ER_TABLESPACE_MISSING));
+ SETMSG(HA_ERR_TABLESPACE_IS_NOT_EMPTY,ER_DEFAULT(ER_TABLESPACE_IS_NOT_EMPTY));
+ SETMSG(HA_ERR_WRONG_FILE_NAME, ER_DEFAULT(ER_WRONG_FILE_NAME));
+ SETMSG(HA_ERR_NOT_ALLOWED_COMMAND, ER_DEFAULT(ER_NOT_ALLOWED_COMMAND));
+ SETMSG(HA_ERR_COMPUTE_FAILED, "Compute virtual column value failed");
+ SETMSG(HA_ERR_INNODB_READ_ONLY, ER_DEFAULT(ER_INNODB_READ_ONLY));
/* Register the error messages for use with my_error(). */
return my_error_register(get_handler_errmsgs, HA_ERR_FIRST, HA_ERR_LAST);
@@ -3525,9 +3536,10 @@ void handler::print_error(int error, myf errflag)
DBUG_VOID_RETURN;
}
case HA_ERR_TABLE_NEEDS_UPGRADE:
+ textno= ER_TABLE_NEEDS_UPGRADE;
my_error(ER_TABLE_NEEDS_UPGRADE, errflag,
"TABLE", table_share->table_name.str);
- break;
+ DBUG_VOID_RETURN;
case HA_ERR_NO_PARTITION_FOUND:
textno=ER_WRONG_PARTITION_NAME;
break;
diff --git a/sql/share/errmsg-utf8.txt b/sql/share/errmsg-utf8.txt
index 8dfa519ba2d..7c3c4ab0ac5 100644
--- a/sql/share/errmsg-utf8.txt
+++ b/sql/share/errmsg-utf8.txt
@@ -7214,3 +7214,21 @@ ER_CALCULATING_DEFAULT_VALUE
eng "Got an error when calculating default value for %`s"
ER_EXPRESSION_REFERS_TO_UNINIT_FIELD 01000
eng "Expression for field %`-.64s is refering to uninitialized field %`s"
+ER_BUFPOOL_RESIZE_INPROGRESS
+ eng "Another buffer pool resize is already in progress."
+ER_CANNOT_DISCARD_TEMPORARY_TABLE
+ eng "Cannot DISCARD/IMPORT tablespace associated with temporary table"
+ER_FK_DEPTH_EXCEEDED
+ eng "Foreign key cascade delete/update exceeds max depth of %d."
+ER_INNODB_FORCED_RECOVERY
+ eng "Operation not allowed when innodb_forced_recovery > 0."
+ER_TABLE_REFERENCED
+ eng "Cannot complete the operation because table is referenced by another connection."
+ER_TABLESPACE_IS_NOT_EMPTY
+ eng "Tablespace `%-.192s` is not empty."
+ER_MISSING_HA_CREATE_OPTION
+ eng "Table storage engine '%-.64s' found required create option missing"
+ER_ENGINE_OUT_OF_MEMORY
+ eng "Out of memory in storage engine '%-.64s'."
+ER_WRONG_FILE_NAME
+ eng "Incorrect File Name '%s'."
diff --git a/storage/innobase/CMakeLists.txt b/storage/innobase/CMakeLists.txt
index b835d6bc0fb..44b1cfa047a 100644
--- a/storage/innobase/CMakeLists.txt
+++ b/storage/innobase/CMakeLists.txt
@@ -1,4 +1,5 @@
-# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2014, 2016, MariaDB Corporation
#
# 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
@@ -30,351 +31,7 @@ MYSQL_CHECK_LZMA()
MYSQL_CHECK_BZIP2()
MYSQL_CHECK_SNAPPY()
-IF(CMAKE_CROSSCOMPILING)
- # Use CHECK_C_SOURCE_COMPILES instead of CHECK_C_SOURCE_RUNS when
- # cross-compiling. Not as precise, but usually good enough.
- # This only make sense for atomic tests in this file, this trick doesn't
- # work in a general case.
- MACRO(CHECK_C_SOURCE SOURCE VAR)
- CHECK_C_SOURCE_COMPILES("${SOURCE}" "${VAR}")
- ENDMACRO()
-ELSE()
- MACRO(CHECK_C_SOURCE SOURCE VAR)
- CHECK_C_SOURCE_RUNS("${SOURCE}" "${VAR}")
- ENDMACRO()
-ENDIF()
-
-# OS tests
-IF(UNIX)
- IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
- CHECK_INCLUDE_FILES (libaio.h HAVE_LIBAIO_H)
- CHECK_LIBRARY_EXISTS(aio io_queue_init "" HAVE_LIBAIO)
- ADD_DEFINITIONS("-DUNIV_LINUX -D_GNU_SOURCE=1")
- IF(HAVE_LIBAIO_H AND HAVE_LIBAIO)
- ADD_DEFINITIONS(-DLINUX_NATIVE_AIO=1)
- LINK_LIBRARIES(aio)
- ENDIF()
- IF(HAVE_LIBNUMA)
- LINK_LIBRARIES(numa)
- ENDIF()
- ELSEIF(CMAKE_SYSTEM_NAME MATCHES "HP*")
- ADD_DEFINITIONS("-DUNIV_HPUX")
- ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "AIX")
- ADD_DEFINITIONS("-DUNIV_AIX")
- ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
- ADD_DEFINITIONS("-DUNIV_SOLARIS")
- ENDIF()
-ENDIF()
-
-IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-# After: WL#5825 Using C++ Standard Library with MySQL code
-# we no longer use -fno-exceptions
-# SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
-ENDIF()
-
-# Enable InnoDB's UNIV_DEBUG and UNIV_SYNC_DEBUG in debug builds
-SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DUNIV_DEBUG -DUNIV_SYNC_DEBUG")
-
-# Add -Wconversion if compiling with GCC
-## As of Mar 15 2011 this flag causes 3573+ warnings. If you are reading this
-## please fix them and enable the following code:
-#IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
-#SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
-#ENDIF()
-
-CHECK_FUNCTION_EXISTS(sched_getcpu HAVE_SCHED_GETCPU)
-IF(HAVE_SCHED_GETCPU)
- ADD_DEFINITIONS(-DHAVE_SCHED_GETCPU)
-ENDIF()
-
-IF(NOT MSVC)
- # either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
- # workaround for gcc 4.1.2 RHEL5/x86, gcc atomic ops only work under -march=i686
- IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" AND CMAKE_COMPILER_IS_GNUCC AND
- CMAKE_C_COMPILER_VERSION VERSION_LESS "4.1.3")
- SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i686")
- SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
- ENDIF()
- CHECK_C_SOURCE(
- "
- int main()
- {
- long x;
- long y;
- long res;
-
- x = 10;
- y = 123;
- res = __sync_bool_compare_and_swap(&x, x, y);
- if (!res || x != y) {
- return(1);
- }
-
- x = 10;
- y = 123;
- res = __sync_bool_compare_and_swap(&x, x + 1, y);
- if (res || x != 10) {
- return(1);
- }
- x = 10;
- y = 123;
- res = __sync_add_and_fetch(&x, y);
- if (res != 123 + 10 || x != 123 + 10) {
- return(1);
- }
- return(0);
- }"
- HAVE_IB_GCC_ATOMIC_BUILTINS
- )
- CHECK_C_SOURCE(
- "
- int main()
- {
- long res;
- char c;
-
- c = 10;
- res = __sync_lock_test_and_set(&c, 123);
- if (res != 10 || c != 123) {
- return(1);
- }
- return(0);
- }"
- HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE
- )
- CHECK_C_SOURCE(
- "#include<stdint.h>
- int main()
- {
- int64_t x,y,res;
-
- x = 10;
- y = 123;
- res = __sync_sub_and_fetch(&y, x);
- if (res != y || y != 113) {
- return(1);
- }
- res = __sync_add_and_fetch(&y, x);
- if (res != y || y != 123) {
- return(1);
- }
- return(0);
- }"
- HAVE_IB_GCC_ATOMIC_BUILTINS_64
- )
- CHECK_C_SOURCE(
- "#include<stdint.h>
- int main()
- {
- __sync_synchronize();
- return(0);
- }"
- HAVE_IB_GCC_SYNC_SYNCHRONISE
- )
- CHECK_C_SOURCE(
- "#include<stdint.h>
- int main()
- {
- __atomic_thread_fence(__ATOMIC_ACQUIRE);
- __atomic_thread_fence(__ATOMIC_RELEASE);
- return(0);
- }"
- HAVE_IB_GCC_ATOMIC_THREAD_FENCE
- )
- CHECK_C_SOURCE(
- "#include<stdint.h>
- int main()
- {
- unsigned char c;
-
- __atomic_test_and_set(&c, __ATOMIC_ACQUIRE);
- __atomic_clear(&c, __ATOMIC_RELEASE);
- return(0);
- }"
- HAVE_IB_GCC_ATOMIC_TEST_AND_SET
- )
-
-IF(HAVE_IB_GCC_ATOMIC_BUILTINS)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_BYTE=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_BUILTINS_64)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_64=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_SYNC_SYNCHRONISE)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_SYNC_SYNCHRONISE=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_THREAD_FENCE)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_THREAD_FENCE=1)
-ENDIF()
-
-IF(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
- ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_TEST_AND_SET=1)
-ENDIF()
-
-# either define HAVE_IB_ATOMIC_PTHREAD_T_GCC or not
-CHECK_C_SOURCE(
-"
-#include <pthread.h>
-#include <string.h>
-
-int main() {
- pthread_t x1;
- pthread_t x2;
- pthread_t x3;
-
- memset(&x1, 0x0, sizeof(x1));
- memset(&x2, 0x0, sizeof(x2));
- memset(&x3, 0x0, sizeof(x3));
-
- __sync_bool_compare_and_swap(&x1, x2, x3);
-
- return(0);
-}"
-HAVE_IB_ATOMIC_PTHREAD_T_GCC)
-
-IF(HAVE_IB_ATOMIC_PTHREAD_T_GCC)
- ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_GCC=1)
-ENDIF()
-
-CHECK_CXX_SOURCE_COMPILES("struct t1{ int a; char *b; }; struct t1 c= { .a=1, .b=0 }; main() { }" HAVE_C99_INITIALIZERS)
-IF(HAVE_C99_INITIALIZERS)
- ADD_DEFINITIONS(-DHAVE_C99_INITIALIZERS)
-ENDIF()
-
-ENDIF(NOT MSVC)
-
-CHECK_FUNCTION_EXISTS(vasprintf HAVE_VASPRINTF)
-
-# Solaris atomics
-IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
- CHECK_FUNCTION_EXISTS(atomic_cas_ulong HAVE_ATOMIC_CAS_ULONG)
- CHECK_FUNCTION_EXISTS(atomic_cas_32 HAVE_ATOMIC_CAS_32)
- CHECK_FUNCTION_EXISTS(atomic_cas_64 HAVE_ATOMIC_CAS_64)
- CHECK_FUNCTION_EXISTS(atomic_add_long_nv HAVE_ATOMIC_ADD_LONG_NV)
- CHECK_FUNCTION_EXISTS(atomic_swap_uchar HAVE_ATOMIC_SWAP_UCHAR)
- IF(HAVE_ATOMIC_CAS_ULONG AND
- HAVE_ATOMIC_CAS_32 AND
- HAVE_ATOMIC_CAS_64 AND
- HAVE_ATOMIC_ADD_LONG_NV AND
- HAVE_ATOMIC_SWAP_UCHAR)
- SET(HAVE_IB_SOLARIS_ATOMICS 1)
- ENDIF()
-
- IF(HAVE_IB_SOLARIS_ATOMICS)
- ADD_DEFINITIONS(-DHAVE_IB_SOLARIS_ATOMICS=1)
- ENDIF()
-
- # either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not
- CHECK_C_SOURCE_COMPILES(
- " #include <pthread.h>
- #include <string.h>
-
- int main(int argc, char** argv) {
- pthread_t x1;
- pthread_t x2;
- pthread_t x3;
-
- memset(&x1, 0x0, sizeof(x1));
- memset(&x2, 0x0, sizeof(x2));
- memset(&x3, 0x0, sizeof(x3));
-
- if (sizeof(pthread_t) == 4) {
-
- atomic_cas_32(&x1, x2, x3);
-
- } else if (sizeof(pthread_t) == 8) {
-
- atomic_cas_64(&x1, x2, x3);
-
- } else {
-
- return(1);
- }
-
- return(0);
- }
- " HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
- CHECK_C_SOURCE_COMPILES(
- "#include <mbarrier.h>
- int main() {
- __machine_r_barrier();
- __machine_w_barrier();
- return(0);
- }"
- HAVE_IB_MACHINE_BARRIER_SOLARIS)
-
- IF(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
- ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_SOLARIS=1)
- ENDIF()
- IF(HAVE_IB_MACHINE_BARRIER_SOLARIS)
- ADD_DEFINITIONS(-DHAVE_IB_MACHINE_BARRIER_SOLARIS=1)
- ENDIF()
-ENDIF()
-
-
-IF(UNIX)
-# this is needed to know which one of atomic_cas_32() or atomic_cas_64()
-# to use in the source
-SET(CMAKE_EXTRA_INCLUDE_FILES pthread.h)
-CHECK_TYPE_SIZE(pthread_t SIZEOF_PTHREAD_T)
-SET(CMAKE_EXTRA_INCLUDE_FILES)
-ENDIF()
-
-IF(SIZEOF_PTHREAD_T)
- ADD_DEFINITIONS(-DSIZEOF_PTHREAD_T=${SIZEOF_PTHREAD_T})
-ENDIF()
-
-IF(MSVC)
- ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS)
- ADD_DEFINITIONS(-DHAVE_WINDOWS_MM_FENCE)
-ENDIF()
-
-SET(MUTEXTYPE "event" CACHE STRING "Mutex type: event, sys or futex")
-
-IF(MUTEXTYPE MATCHES "event")
- ADD_DEFINITIONS(-DMUTEX_EVENT)
-ELSEIF(MUTEXTYPE MATCHES "futex" AND DEFINED HAVE_IB_LINUX_FUTEX)
- ADD_DEFINITIONS(-DMUTEX_FUTEX)
-ELSE()
- ADD_DEFINITIONS(-DMUTEX_SYS)
-ENDIF()
-
-# Include directories under innobase
-INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include
- ${CMAKE_SOURCE_DIR}/storage/innobase/handler)
-
-# Sun Studio bug with -xO2
-IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro"
- AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2"
- AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
- # Sun Studio 12 crashes with -xO2 flag, but not with higher optimization
- # -xO3
- SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/rem/rem0rec.cc
- PROPERTIES COMPILE_FLAGS -xO3)
-ENDIF()
-
-# Removing compiler optimizations for innodb/mem/* files on 64-bit Windows
-# due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297
-IF (MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
- SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.cc mem/mem0pool.cc
- PROPERTIES COMPILE_FLAGS -Od)
-ENDIF()
-
-IF(MSVC)
- # Avoid "unreferenced label" warning in generated file
- GET_FILENAME_COMPONENT(_SRC_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
- SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/pars0grm.c
- PROPERTIES COMPILE_FLAGS "/wd4102")
- SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/lexyy.c
- PROPERTIES COMPILE_FLAGS "/wd4003")
-ENDIF()
+INCLUDE(innodb.cmake)
SET(INNOBASE_SOURCES
api/api0api.cc
@@ -404,7 +61,7 @@ SET(INNOBASE_SOURCES
dict/dict0mem.cc
dict/dict0stats.cc
dict/dict0stats_bg.cc
-# dyn/dyn0dyn.cc
+ dict/dict0defrag_bg.cc
eval/eval0eval.cc
eval/eval0proc.cc
fil/fil0fil.cc
@@ -425,34 +82,32 @@ SET(INNOBASE_SOURCES
fts/fts0config.cc
fts/fts0opt.cc
fts/fts0pars.cc
- fts/fts0plugin.cc
fts/fts0que.cc
fts/fts0sql.cc
fts/fts0tlex.cc
gis/gis0geo.cc
gis/gis0rtree.cc
gis/gis0sea.cc
+ fts/fts0plugin.cc
handler/ha_innodb.cc
# handler/ha_innopart.cc
handler/handler0alter.cc
handler/i_s.cc
ibuf/ibuf0ibuf.cc
lock/lock0iter.cc
- lock/lock0lock.cc
lock/lock0prdt.cc
+ lock/lock0lock.cc
lock/lock0wait.cc
log/log0log.cc
log/log0recv.cc
log/log0crypt.cc
mach/mach0data.cc
mem/mem0mem.cc
-# mem/mem0pool.cc
mtr/mtr0log.cc
mtr/mtr0mtr.cc
- os/os0event.cc
os/os0file.cc
os/os0proc.cc
-# os/os0sync.cc
+ os/os0event.cc
os/os0thread.cc
page/page0cur.cc
page/page0page.cc
@@ -488,8 +143,8 @@ SET(INNOBASE_SOURCES
srv/srv0srv.cc
srv/srv0start.cc
sync/sync0arr.cc
- sync/sync0debug.cc
sync/sync0rw.cc
+ sync/sync0debug.cc
sync/sync0sync.cc
trx/trx0i_s.cc
trx/trx0purge.cc
@@ -500,7 +155,6 @@ SET(INNOBASE_SOURCES
trx/trx0trx.cc
trx/trx0undo.cc
usr/usr0sess.cc
-# ut/ut0bh.cc
ut/ut0byte.cc
ut/ut0crc32.cc
ut/ut0dbg.cc
@@ -527,19 +181,42 @@ IF(WITH_INNODB)
SET(WITH_INNOBASE_STORAGE_ENGINE TRUE)
ENDIF()
-# On solaris, reduce symbol visibility, so loader does not mix
-# the same symbols from builtin innodb and from shared one.
-# Only required for old GCC (3.4.3) that does not support hidden visibility
-IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_COMPILER_IS_GNUCC
- AND NOT HAVE_VISIBILITY_HIDDEN)
- SET(LINKER_SCRIPT "-Wl,-M${CMAKE_CURRENT_SOURCE_DIR}/plugin_exports")
-ELSE()
- SET(LINKER_SCRIPT)
-ENDIF()
-
MYSQL_ADD_PLUGIN(innobase ${INNOBASE_SOURCES} STORAGE_ENGINE
# MODULE_ONLY
# MODULE_OUTPUT_NAME ha_innodb
DEFAULT RECOMPILE_FOR_EMBEDDED
LINK_LIBRARIES ${ZLIB_LIBRARY} ${LINKER_SCRIPT})
+IF(WITH_INNOBASE_STORAGE_ENGINE)
+ ADD_DEPENDENCIES(innobase GenError)
+ENDIF()
+
+# Avoid generating Hardware Capabilities due to crc32 instructions
+IF(CMAKE_SYSTEM_NAME MATCHES "SunOS" AND CMAKE_SYSTEM_PROCESSOR MATCHES "i386")
+ INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/compile_flags.cmake)
+ MY_CHECK_CXX_COMPILER_FLAG("-Wa,-nH" HAVE_WA_NH)
+ IF(HAVE_WA_NH)
+ ADD_COMPILE_FLAGS(
+ ut/ut0crc32.cc
+ COMPILE_FLAGS "-Wa,-nH"
+ )
+ ENDIF()
+ENDIF()
+
+# A GCC bug causes crash when compiling these files on ARM64 with -O1+
+# Compile them with -O0 as a workaround.
+IF(CMAKE_COMPILER_IS_GNUCXX AND CMAKE_SYSTEM_PROCESSOR MATCHES "aarch64")
+ # Bug was fixed in GCC 5.2, so workaround only needed < 5.2
+ EXECUTE_PROCESS(COMMAND ${CMAKE_C_COMPILER} -dumpversion
+ OUTPUT_VARIABLE GCC_VERSION)
+ IF(GCC_VERSION VERSION_LESS 5.2)
+ INCLUDE(${MYSQL_CMAKE_SCRIPT_DIR}/compile_flags.cmake)
+ ADD_COMPILE_FLAGS(
+ btr/btr0btr.cc
+ btr/btr0cur.cc
+ buf/buf0buf.cc
+ gis/gis0sea.cc
+ COMPILE_FLAGS "-O0"
+ )
+ ENDIF()
+ENDIF()
diff --git a/storage/innobase/api/api0api.cc b/storage/innobase/api/api0api.cc
index 1f04b1b1234..1b99dcf1564 100644
--- a/storage/innobase/api/api0api.cc
+++ b/storage/innobase/api/api0api.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2008, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2008, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1006,6 +1006,16 @@ ib_cursor_open_table(
return(err);
}
+/** Check the table whether it contains virtual columns.
+@param[in] crsr InnoDB Cursor
+@return true if table contains virtual column else false. */
+ib_bool_t
+ib_is_virtual_table(
+ ib_crsr_t crsr)
+{
+ return(crsr->prebuilt->table->n_v_cols > 0);
+}
+
/********************************************************************//**
Free a context struct for a table handle. */
static
@@ -1262,12 +1272,14 @@ ib_insert_query_graph_create(
row = dtuple_create(heap, dict_table_get_n_cols(table));
dict_table_copy_types(row, table);
+ ut_ad(!dict_table_have_virtual_index(table));
+
ins_node_set_new_row(node->ins, row);
grph->ins = static_cast<que_fork_t*>(
que_node_get_parent(
pars_complete_graph_for_exec(node->ins, trx,
- heap)));
+ heap, NULL)));
grph->ins->state = QUE_FORK_ACTIVE;
}
@@ -1376,9 +1388,12 @@ ib_update_vector_create(
row_create_update_node_for_mysql(table, heap));
}
+ ut_ad(!dict_table_have_virtual_index(table));
+
grph->upd = static_cast<que_fork_t*>(
que_node_get_parent(
- pars_complete_graph_for_exec(node->upd, trx, heap)));
+ pars_complete_graph_for_exec(node->upd, trx,
+ heap, NULL)));
grph->upd->state = QUE_FORK_ACTIVE;
@@ -3009,12 +3024,13 @@ ib_table_lock(
}
ut_a(ib_lck_mode <= static_cast<ib_lck_mode_t>(LOCK_NUM));
+ ut_ad(!dict_table_have_virtual_index(table));
heap = mem_heap_create(128);
q_proc.node.sel = sel_node_create(heap);
- thr = pars_complete_graph_for_exec(q_proc.node.sel, trx, heap);
+ thr = pars_complete_graph_for_exec(q_proc.node.sel, trx, heap, NULL);
q_proc.grph.sel = static_cast<que_fork_t*>(que_node_get_parent(thr));
q_proc.grph.sel->state = QUE_FORK_ACTIVE;
diff --git a/storage/innobase/api/api0misc.cc b/storage/innobase/api/api0misc.cc
index c83eaedad6e..3864e4b9a7f 100644
--- a/storage/innobase/api/api0misc.cc
+++ b/storage/innobase/api/api0misc.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2008, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2008, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -45,69 +45,9 @@ ib_trx_lock_table_with_retry(
dict_table_t* table, /*!< in: table to lock */
enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */
{
- que_thr_t* thr;
- dberr_t err;
- mem_heap_t* heap;
- sel_node_t* node;
-
- heap = mem_heap_create(512);
-
trx->op_info = "setting table lock";
- node = sel_node_create(heap);
- thr = pars_complete_graph_for_exec(node, trx, heap);
- thr->graph->state = QUE_FORK_ACTIVE;
-
- /* We use the select query graph as the dummy graph needed
- in the lock module call */
-
- thr = que_fork_get_first_thr(static_cast<que_fork_t*>(
- que_node_get_parent(thr)));
- que_thr_move_to_run_state_for_mysql(thr, trx);
-
-run_again:
- thr->run_node = thr;
- thr->prev_node = thr->common.parent;
-
- err = lock_table(0, table, mode, thr);
-
- trx->error_state = err;
-
- if (UNIV_LIKELY(err == DB_SUCCESS)) {
- que_thr_stop_for_mysql_no_error(thr, trx);
- } else {
- que_thr_stop_for_mysql(thr);
-
- if (err != DB_QUE_THR_SUSPENDED) {
- ibool was_lock_wait;
-
- was_lock_wait = ib_handle_errors(&err, trx, thr, NULL);
-
- if (was_lock_wait) {
- goto run_again;
- }
- } else {
- que_thr_t* run_thr;
- que_node_t* parent;
-
- parent = que_node_get_parent(thr);
- run_thr = que_fork_start_command(
- static_cast<que_fork_t*>(parent));
-
- ut_a(run_thr == thr);
-
- /* There was a lock wait but the thread was not
- in a ready to run or running state. */
- trx->error_state = DB_LOCK_WAIT;
-
- goto run_again;
- }
- }
-
- que_graph_free(thr->graph);
- trx->op_info = "";
-
- return(err);
+ return(lock_table_for_trx(table, trx, mode));
}
/****************************************************************//**
Handles user errors and lock waits detected by the database engine.
diff --git a/storage/innobase/btr/btr0btr.cc b/storage/innobase/btr/btr0btr.cc
index 36ec01d7b3d..255788229e4 100644
--- a/storage/innobase/btr/btr0btr.cc
+++ b/storage/innobase/btr/btr0btr.cc
@@ -338,8 +338,10 @@ btr_root_adjust_on_import(
} else {
/* Check that the table flags and the tablespace
flags match. */
- ulint flags = dict_tf_to_fsp_flags(table->flags,
- false);
+ ulint flags = dict_tf_to_fsp_flags(
+ table->flags,
+ false,
+ dict_table_is_encrypted(table));
ulint fsp_flags = fil_space_get_flags(table->space);
err = fsp_flags_are_equal(flags, fsp_flags)
? DB_SUCCESS : DB_CORRUPTION;
@@ -910,6 +912,7 @@ btr_page_get_father_node_ptr_func(
page_no = btr_cur_get_block(cursor)->page.id.page_no();
index = btr_cur_get_index(cursor);
+ ut_ad(!dict_index_is_spatial(index));
ut_ad(srv_read_only_mode
|| mtr_memo_contains_flagged(mtr, dict_index_get_lock(index),
@@ -923,44 +926,33 @@ btr_page_get_father_node_ptr_func(
user_rec = btr_cur_get_rec(cursor);
ut_a(page_rec_is_user_rec(user_rec));
- tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
- if (!dict_index_is_spatial(index)) {
- dberr_t err = DB_SUCCESS;
- if (dict_table_is_intrinsic(index->table)) {
- err = btr_cur_search_to_nth_level_with_no_latch(
- index, level + 1, tuple, PAGE_CUR_LE, cursor,
- file, line, mtr);
- } else {
- err = btr_cur_search_to_nth_level(
- index, level + 1, tuple,
- PAGE_CUR_LE, latch_mode, cursor, 0,
- file, line, mtr);
- }
-
- if (err != DB_SUCCESS) {
- ib::warn() << " Error code: " << err
- << " btr_page_get_father_node_ptr_func "
- << " level: " << level + 1
- << " called from file: "
- << file << " line: " << line
- << " table: " << index->table->name
- << " index: " << index->name;
- }
+ tuple = dict_index_build_node_ptr(index, user_rec, 0, heap, level);
+ dberr_t err = DB_SUCCESS;
+
+ if (dict_table_is_intrinsic(index->table)) {
+ err = btr_cur_search_to_nth_level_with_no_latch(
+ index, level + 1, tuple, PAGE_CUR_LE, cursor,
+ file, line, mtr);
} else {
- /* For R-tree, only latch mode from caller would be
- BTR_CONT_MODIFY_TREE */
- ut_ad(latch_mode == BTR_CONT_MODIFY_TREE);
+ err = btr_cur_search_to_nth_level(
+ index, level + 1, tuple,
+ PAGE_CUR_LE, latch_mode, cursor, 0,
+ file, line, mtr);
+ }
- /* Try to avoid traverse from the root, and get the
- father node from parent_path vector */
- rtr_get_father_node(index, level + 1, tuple,
- NULL, cursor, page_no, mtr);
+ if (err != DB_SUCCESS) {
+ ib::warn() << " Error code: " << err
+ << " btr_page_get_father_node_ptr_func "
+ << " level: " << level + 1
+ << " called from file: "
+ << file << " line: " << line
+ << " table: " << index->table->name
+ << " index: " << index->name();
}
node_ptr = btr_cur_get_rec(cursor);
- ut_ad(!page_rec_is_comp(node_ptr)
- || rec_get_status(node_ptr) == REC_STATUS_NODE_PTR);
+
offsets = rec_get_offsets(node_ptr, index, offsets,
ULINT_UNDEFINED, &heap);
@@ -1106,7 +1098,7 @@ btr_free_root_invalidate(
@param[in,out] mtr mini-transaction
@return root block, to invoke btr_free_but_not_root() and btr_free_root()
@retval NULL if the page is no longer a matching B-tree page */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
buf_block_t*
btr_free_root_check(
const page_id_t& page_id,
@@ -1654,7 +1646,6 @@ IBUF_BITMAP_FREE is unaffected by reorganization.
@retval true if the operation was successful
@retval false if it is a compressed page, and recompression failed */
-UNIV_INTERN
bool
btr_page_reorganize_block(
/*======================*/
@@ -1782,7 +1773,7 @@ the tuple. It is assumed that mtr contains an x-latch on the tree.
NOTE that the operation of this function must always succeed,
we cannot reverse it: therefore enough free disk space must be
guaranteed to be available before this function is called.
-@return inserted record or NULL if run out of space */
+@return inserted record */
rec_t*
btr_root_raise_and_insert(
/*======================*/
@@ -1848,7 +1839,7 @@ btr_root_raise_and_insert(
if (new_block == NULL && os_has_said_disk_full) {
return(NULL);
- }
+ }
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
@@ -2719,7 +2710,6 @@ released within this function! NOTE that the operation of this
function must always succeed, we cannot reverse it: therefore enough
free disk space (2 pages) must be guaranteed to be available before
this function is called.
-
NOTE: jonaso added support for calling function with tuple == NULL
which cause it to only split a page.
@@ -2850,7 +2840,7 @@ func_start:
DBUG_EXECUTE_IF("disk_is_full",
os_has_said_disk_full = true;
- return(NULL););
+ return(NULL););
/* 2. Allocate a new page to the index */
new_block = btr_page_alloc(cursor->index, hint_page_no, direction,
@@ -2858,7 +2848,7 @@ func_start:
if (new_block == NULL && os_has_said_disk_full) {
return(NULL);
- }
+ }
new_page = buf_block_get_frame(new_block);
new_page_zip = buf_block_get_page_zip(new_block);
@@ -3164,7 +3154,6 @@ func_exit:
@param[in,out] page page to remove
@param[in] index index tree
@param[in,out] mtr mini-transaction */
-UNIV_INTERN
void
btr_level_list_remove_func(
ulint space,
@@ -3369,8 +3358,15 @@ btr_lift_page_up(
* (REC_OFFS_HEADER_SIZE + 1 + 1 + index->n_fields));
buf_block_t* b;
- offsets = btr_page_get_father_block(offsets, heap, index,
- block, mtr, &cursor);
+ if (dict_index_is_spatial(index)) {
+ offsets = rtr_page_get_father_block(
+ NULL, heap, index, block, mtr,
+ NULL, &cursor);
+ } else {
+ offsets = btr_page_get_father_block(offsets, heap,
+ index, block,
+ mtr, &cursor);
+ }
father_block = btr_cur_get_block(&cursor);
father_page_zip = buf_block_get_page_zip(father_block);
father_page = buf_block_get_frame(father_block);
@@ -3386,9 +3382,17 @@ btr_lift_page_up(
b->page.id.page_no() != root_page_no; ) {
ut_a(n_blocks < BTR_MAX_LEVELS);
- offsets = btr_page_get_father_block(offsets, heap,
- index, b,
- mtr, &cursor);
+ if (dict_index_is_spatial(index)) {
+ offsets = rtr_page_get_father_block(
+ NULL, heap, index, b, mtr,
+ NULL, &cursor);
+ } else {
+ offsets = btr_page_get_father_block(offsets,
+ heap,
+ index, b,
+ mtr,
+ &cursor);
+ }
blocks[n_blocks++] = b = btr_cur_get_block(&cursor);
}
@@ -3460,6 +3464,13 @@ btr_lift_page_up(
}
if (!dict_table_is_locking_disabled(index->table)) {
+ /* Free predicate page locks on the block */
+ if (dict_index_is_spatial(index)) {
+ lock_mutex_enter();
+ lock_prdt_page_free_from_discard(
+ block, lock_sys->prdt_page_hash);
+ lock_mutex_exit();
+ }
lock_update_copy_and_discard(father_block, block);
}
@@ -3686,6 +3697,11 @@ retry:
goto retry;
}
+ /* Set rtr_info for cursor2, since it is
+ necessary in recursive page merge. */
+ cursor2.rtr_info = cursor->rtr_info;
+ cursor2.tree_height = cursor->tree_height;
+
offsets2 = rec_get_offsets(
btr_cur_get_rec(&cursor2), index,
NULL, ULINT_UNDEFINED, &heap);
@@ -3744,6 +3760,8 @@ retry:
/* No GAP lock needs to be worrying about */
lock_mutex_enter();
+ lock_prdt_page_free_from_discard(
+ block, lock_sys->prdt_page_hash);
lock_rec_free_all_from_discard_page(block);
lock_mutex_exit();
} else {
@@ -3781,6 +3799,11 @@ retry:
merge_block, heap)) {
goto err_exit;
}
+
+ /* Set rtr_info for cursor2, since it is
+ necessary in recursive page merge. */
+ cursor2.rtr_info = cursor->rtr_info;
+ cursor2.tree_height = cursor->tree_height;
} else {
btr_page_get_father(index, merge_block, mtr, &cursor2);
}
@@ -3858,6 +3881,8 @@ retry:
/* For rtree, we need to update father's mbr. */
if (dict_index_is_spatial(index)) {
ulint* offsets2;
+ ulint rec_info;
+
offsets2 = rec_get_offsets(
btr_cur_get_rec(&cursor2),
index, NULL, ULINT_UNDEFINED, &heap);
@@ -3866,12 +3891,34 @@ retry:
btr_cur_get_rec(&cursor2), offsets2)
== right_page_no);
- rtr_merge_and_update_mbr(&father_cursor,
- &cursor2,
- offsets, offsets2,
- merge_page, merge_block,
- block, index, mtr);
+ rec_info = rec_get_info_bits(
+ btr_cur_get_rec(&father_cursor),
+ rec_offs_comp(offsets));
+ if (rec_info & REC_INFO_MIN_REC_FLAG) {
+ /* When the father node ptr is minimal rec,
+ we will keep it and delete the node ptr of
+ merge page. */
+ rtr_merge_and_update_mbr(&father_cursor,
+ &cursor2,
+ offsets, offsets2,
+ merge_page,
+ merge_block,
+ block, index, mtr);
+ } else {
+ /* Otherwise, we will keep the node ptr of
+ merge page and delete the father node ptr.
+ This is for keeping the rec order in upper
+ level. */
+ rtr_merge_and_update_mbr(&cursor2,
+ &father_cursor,
+ offsets2, offsets,
+ merge_page,
+ merge_block,
+ block, index, mtr);
+ }
lock_mutex_enter();
+ lock_prdt_page_free_from_discard(
+ block, lock_sys->prdt_page_hash);
lock_rec_free_all_from_discard_page(block);
lock_mutex_exit();
} else {
@@ -4028,9 +4075,10 @@ btr_discard_only_page_on_level(
if (dict_index_is_spatial(index)) {
/* Check any concurrent search having this page */
rtr_check_discard_page(index, NULL, block);
+ rtr_page_get_father(index, block, mtr, NULL, &cursor);
+ } else {
+ btr_page_get_father(index, block, mtr, &cursor);
}
-
- btr_page_get_father(index, block, mtr, &cursor);
father = btr_cur_get_block(&cursor);
if (!dict_table_is_locking_disabled(index->table)) {
@@ -4114,7 +4162,11 @@ btr_discard_page(
MONITOR_INC(MONITOR_INDEX_DISCARD);
#ifdef UNIV_DEBUG
- btr_page_get_father(index, block, mtr, &parent_cursor);
+ if (dict_index_is_spatial(index)) {
+ rtr_page_get_father(index, block, mtr, cursor, &parent_cursor);
+ } else {
+ btr_page_get_father(index, block, mtr, &parent_cursor);
+ }
#endif
/* Decide the page which will inherit the locks */
@@ -4178,10 +4230,20 @@ btr_discard_page(
btr_set_min_rec_mark(node_ptr, mtr);
}
- btr_node_ptr_delete(index, block, mtr);
+ if (dict_index_is_spatial(index)) {
+ btr_cur_t father_cursor;
+
+ /* Since rtr_node_ptr_delete doesn't contain get father
+ node ptr, so, we need to get father node ptr first and then
+ delete it. */
+ rtr_page_get_father(index, block, mtr, cursor, &father_cursor);
+ rtr_node_ptr_delete(index, &father_cursor, block, mtr);
+ } else {
+ btr_node_ptr_delete(index, block, mtr);
+ }
/* Remove the page from the level list */
- btr_level_list_remove(space, page_size, (page_t*)page, index, mtr);
+ btr_level_list_remove(space, page_size, page, index, mtr);
#ifdef UNIV_ZIP_DEBUG
{
@@ -4377,8 +4439,14 @@ btr_check_node_ptr(
}
heap = mem_heap_create(256);
- offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
- &cursor);
+
+ if (dict_index_is_spatial(index)) {
+ offsets = rtr_page_get_father_block(NULL, heap, index, block, mtr,
+ NULL, &cursor);
+ } else {
+ offsets = btr_page_get_father_block(NULL, heap, index, block, mtr,
+ &cursor);
+ }
if (page_is_leaf(page)) {
diff --git a/storage/innobase/btr/btr0bulk.cc b/storage/innobase/btr/btr0bulk.cc
index 4a3de744823..9ff3bc5f6d1 100644
--- a/storage/innobase/btr/btr0bulk.cc
+++ b/storage/innobase/btr/btr0bulk.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -641,7 +641,7 @@ BtrBulk::pageSplit(
/* 1. Check if we have only one user record on the page. */
if (page_bulk->getRecNo() <= 1) {
- return DB_TOO_BIG_RECORD;
+ return(DB_TOO_BIG_RECORD);
}
/* 2. create a new page. */
@@ -771,6 +771,7 @@ BtrBulk::insert(
ulint level)
{
bool is_left_most = false;
+ dberr_t err = DB_SUCCESS;
ut_ad(m_heap != NULL);
@@ -779,7 +780,7 @@ BtrBulk::insert(
PageBulk* new_page_bulk
= UT_NEW_NOKEY(PageBulk(m_index, m_trx_id, FIL_NULL,
level, m_flush_observer));
- dberr_t err = new_page_bulk->init();
+ err = new_page_bulk->init();
if (err != DB_SUCCESS) {
return(err);
}
@@ -806,29 +807,37 @@ BtrBulk::insert(
ulint n_ext = 0;
ulint rec_size = rec_get_converted_size(m_index, tuple, n_ext);
big_rec_t* big_rec = NULL;
+ rec_t* rec = NULL;
+ ulint* offsets = NULL;
if (page_bulk->needExt(tuple, rec_size)) {
/* The record is so big that we have to store some fields
externally on separate database pages */
big_rec = dtuple_convert_big_rec(m_index, 0, tuple, &n_ext);
- if (UNIV_UNLIKELY(big_rec == NULL)) {
+ if (big_rec == NULL) {
return(DB_TOO_BIG_RECORD);
}
rec_size = rec_get_converted_size(m_index, tuple, n_ext);
}
+ if (page_bulk->getPageZip() != NULL
+ && page_zip_is_too_big(m_index, tuple)) {
+ err = DB_TOO_BIG_RECORD;
+ goto func_exit;
+ }
+
if (!page_bulk->isSpaceAvailable(rec_size)) {
/* Create a sibling page_bulk. */
PageBulk* sibling_page_bulk;
sibling_page_bulk = UT_NEW_NOKEY(PageBulk(m_index, m_trx_id,
FIL_NULL, level,
m_flush_observer));
- dberr_t err = sibling_page_bulk->init();
+ err = sibling_page_bulk->init();
if (err != DB_SUCCESS) {
UT_DELETE(sibling_page_bulk);
- return(err);
+ goto func_exit;
}
/* Commit page bulk. */
@@ -836,7 +845,7 @@ BtrBulk::insert(
if (err != DB_SUCCESS) {
pageAbort(sibling_page_bulk);
UT_DELETE(sibling_page_bulk);
- return(err);
+ goto func_exit;
}
/* Set new page bulk to page_bulks. */
@@ -850,7 +859,8 @@ BtrBulk::insert(
if (page_is_leaf(sibling_page_bulk->getPage())) {
/* Check whether trx is interrupted */
if (m_flush_observer->check_interrupted()) {
- return(DB_INTERRUPTED);
+ err = DB_INTERRUPTED;
+ goto func_exit;
}
/* Wake up page cleaner to flush dirty pages. */
@@ -862,8 +872,6 @@ BtrBulk::insert(
}
- rec_t* rec;
- ulint* offsets = NULL;
/* Convert tuple to rec. */
rec = rec_convert_dtuple_to_rec(static_cast<byte*>(mem_heap_alloc(
page_bulk->m_heap, rec_size)), m_index, tuple, n_ext);
@@ -873,8 +881,6 @@ BtrBulk::insert(
page_bulk->insert(rec, offsets);
if (big_rec != NULL) {
- dberr_t err;
-
ut_ad(dict_index_is_clust(m_index));
ut_ad(page_bulk->getLevel() == 0);
ut_ad(page_bulk == m_page_bulks->at(0));
@@ -893,13 +899,14 @@ BtrBulk::insert(
PageBulk* page_bulk = m_page_bulks->at(level);
page_bulk->latch();
}
+ }
+func_exit:
+ if (big_rec != NULL) {
dtuple_convert_back_big_rec(m_index, tuple, big_rec);
-
- return(err);
}
- return(DB_SUCCESS);
+ return(err);
}
/** Btree bulk load finish. We commit the last page in each level
diff --git a/storage/innobase/btr/btr0cur.cc b/storage/innobase/btr/btr0cur.cc
index ab8ee1d443c..7daec068f78 100644
--- a/storage/innobase/btr/btr0cur.cc
+++ b/storage/innobase/btr/btr0cur.cc
@@ -723,7 +723,6 @@ If mode is PAGE_CUR_LE , cursor is left at the place where an insert of the
search tuple should be performed in the B-tree. InnoDB does an insert
immediately after the cursor. Thus, the cursor may end up on a user record,
or on a page infimum record. */
-UNIV_INTERN
dberr_t
btr_cur_search_to_nth_level(
/*========================*/
@@ -1412,7 +1411,11 @@ retry_page_get:
level, the search becomes PAGE_CUR_LE */
if (page_mode == PAGE_CUR_RTREE_LOCATE
&& level == height) {
- page_mode = PAGE_CUR_LE;
+ if (level == 0) {
+ page_mode = PAGE_CUR_LE;
+ } else {
+ page_mode = PAGE_CUR_RTREE_GET_FATHER;
+ }
}
if (page_mode == PAGE_CUR_RTREE_INSERT) {
@@ -1463,6 +1466,11 @@ retry_page_get:
ut_ad(0);
}
}
+
+ if (found && page_mode == PAGE_CUR_RTREE_GET_FATHER) {
+ cursor->low_match =
+ DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1;
+ }
} else if (height == 0 && btr_search_enabled
&& !dict_index_is_spatial(index)) {
/* The adaptive hash index is only used when searching
@@ -2102,7 +2110,7 @@ btr_cur_search_to_nth_level_with_no_latch(
ut_ad(n_blocks < BTR_MAX_LEVELS);
block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
- buf_mode, file, line, mtr, &err, mark_dirty);
+ buf_mode, file, line, mtr, &err, mark_dirty);
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
@@ -2115,7 +2123,7 @@ btr_cur_search_to_nth_level_with_no_latch(
index->table->is_encrypted = true;
}
- return (err);
+ DBUG_RETURN(err);
}
page = buf_block_get_frame(block);
@@ -2171,7 +2179,7 @@ btr_cur_search_to_nth_level_with_no_latch(
mem_heap_free(heap);
}
- return err;
+ DBUG_RETURN(err);
}
/*****************************************************************//**
@@ -2578,7 +2586,6 @@ btr_cur_open_at_index_side_with_no_latch_func(
ulint offsets_[REC_OFFS_NORMAL_SIZE];
ulint* offsets = offsets_;
dberr_t err = DB_SUCCESS;
-
rec_offs_init(offsets_);
ut_ad(level != ULINT_UNDEFINED);
@@ -2599,7 +2606,7 @@ btr_cur_open_at_index_side_with_no_latch_func(
ut_ad(n_blocks < BTR_MAX_LEVELS);
block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
- BUF_GET, file, line, mtr, &err);
+ BUF_GET, file, line, mtr, &err);
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
@@ -2665,7 +2672,7 @@ btr_cur_open_at_index_side_with_no_latch_func(
mem_heap_free(heap);
}
- return (err);
+ return(err);
}
/**********************************************************************//**
@@ -2759,6 +2766,7 @@ btr_cur_open_at_rnd_pos_func(
page_id_t page_id(dict_index_get_space(index),
dict_index_get_page(index));
const page_size_t& page_size = dict_table_page_size(index->table);
+ dberr_t err = DB_SUCCESS;
if (root_leaf_rw_latch == RW_X_LATCH) {
node_ptr_max_size = dict_index_node_ptr_max_size(index);
@@ -2769,7 +2777,6 @@ btr_cur_open_at_rnd_pos_func(
for (;;) {
buf_block_t* block;
page_t* page;
- dberr_t err=DB_SUCCESS;
ulint rw_latch;
ut_ad(n_blocks < BTR_MAX_LEVELS);
@@ -2783,10 +2790,9 @@ btr_cur_open_at_rnd_pos_func(
tree_savepoints[n_blocks] = mtr_set_savepoint(mtr);
block = buf_page_get_gen(page_id, page_size, rw_latch, NULL,
- BUF_GET, file, line, mtr, &err);
+ BUF_GET, file, line, mtr, &err);
tree_blocks[n_blocks] = block;
-
if (err != DB_SUCCESS) {
if (err == DB_DECRYPTION_FAILED) {
ib_push_warning((void *)NULL,
@@ -3222,46 +3228,12 @@ btr_cur_optimistic_insert(
rec_size = rec_get_converted_size(index, entry, n_ext);
}
- if (page_size.is_compressed()) {
- /* Estimate the free space of an empty compressed page.
- Subtract one byte for the encoded heap_no in the
- modification log. */
- ulint free_space_zip = page_zip_empty_size(
- cursor->index->n_fields, page_size.physical());
- ulint n_uniq = dict_index_get_n_unique_in_tree(index);
-
- ut_ad(dict_table_is_comp(index->table));
-
- if (free_space_zip == 0) {
-too_big:
- if (big_rec_vec) {
- dtuple_convert_back_big_rec(
- index, entry, big_rec_vec);
- }
-
- return(DB_TOO_BIG_RECORD);
+ if (page_size.is_compressed() && page_zip_is_too_big(index, entry)) {
+ if (big_rec_vec != NULL) {
+ dtuple_convert_back_big_rec(index, entry, big_rec_vec);
}
- /* Subtract one byte for the encoded heap_no in the
- modification log. */
- free_space_zip--;
-
- /* There should be enough room for two node pointer
- records on an empty non-leaf page. This prevents
- infinite page splits. */
-
- if (entry->n_fields >= n_uniq
- && (REC_NODE_PTR_SIZE
- + rec_get_converted_size_comp_prefix(
- index, entry->fields, n_uniq, NULL)
- /* On a compressed page, there is
- a two-byte entry in the dense
- page directory for every record.
- But there is no record header. */
- - (REC_N_NEW_EXTRA_BYTES - 2)
- > free_space_zip / 2)) {
- goto too_big;
- }
+ return(DB_TOO_BIG_RECORD);
}
LIMIT_OPTIMISTIC_INSERT_DEBUG(page_get_n_recs(page),
@@ -3323,12 +3295,12 @@ fail_err:
#ifdef UNIV_DEBUG
{
rec_printer p(entry);
- DBUG_PRINT("ib_cur", ("insert %s (%llu) by %lu %s",
- index->name(), index->id,
- thr != NULL
- ? trx_get_id_for_print(thr_get_trx(thr))
- : 0,
- p.str().c_str()));
+ DBUG_PRINT("ib_cur", ("insert %s (" IB_ID_FMT ") by " IB_ID_FMT " %s",
+ index->name(), index->id,
+ thr != NULL
+ ? trx_get_id_for_print(thr_get_trx(thr))
+ : 0,
+ p.str().c_str()));
}
#endif
@@ -3350,7 +3322,6 @@ fail_err:
if specified */
err = btr_cur_ins_lock_and_undo(flags, cursor, entry,
thr, mtr, &inherit);
-
if (err != DB_SUCCESS) {
goto fail_err;
}
@@ -3592,6 +3563,7 @@ btr_cur_pessimistic_insert(
btr_cur_get_page_zip(cursor),
thr_get_trx(thr)->id, mtr);
}
+
if (!page_rec_is_infimum(btr_cur_get_rec(cursor))
|| btr_page_get_prev(
buf_block_get_frame(
@@ -3601,18 +3573,6 @@ btr_cur_pessimistic_insert(
lock_update_insert() always. */
inherit = TRUE;
}
-
- buf_block_t* block = btr_cur_get_block(cursor);
- buf_frame_t* frame = NULL;
-
- if (block) {
- frame = buf_block_get_frame(block);
- }
- /* split and inserted need to call
- lock_update_insert() always. */
- if (frame && btr_page_get_prev(frame, mtr) == FIL_NULL) {
- inherit = TRUE;
- }
}
}
@@ -3640,7 +3600,7 @@ btr_cur_pessimistic_insert(
/*************************************************************//**
For an update, checks the locks and does the undo logging.
@return DB_SUCCESS, DB_WAIT_LOCK, or error number */
-UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(2,3,6,7)))
+UNIV_INLINE MY_ATTRIBUTE((warn_unused_result))
dberr_t
btr_cur_upd_lock_and_undo(
/*======================*/
@@ -3978,7 +3938,7 @@ btr_cur_update_in_place(
#ifdef UNIV_DEBUG
{
rec_printer p(rec, offsets);
- DBUG_PRINT("ib_cur", ("update-in-place %s (%llu) by %lu: %s",
+ DBUG_PRINT("ib_cur", ("update-in-place %s (" IB_ID_FMT ") by "IB_ID_FMT ": %s",
index->name(), index->id, trx_id,
p.str().c_str()));
}
@@ -4186,8 +4146,8 @@ any_extern:
#ifdef UNIV_DEBUG
{
rec_printer p(rec, *offsets);
- DBUG_PRINT("ib_cur", ("update %s (%llu) by %lu: %s",
- index->name(), index->id, trx_id,
+ DBUG_PRINT("ib_cur", ("update %s (" IB_ID_FMT ") by " IB_ID_FMT ": %s",
+ index->name(), index->id, trx_id,
p.str().c_str()));
}
#endif
@@ -5026,7 +4986,7 @@ btr_cur_del_mark_set_clust_rec(
#ifdef UNIV_DEBUG
{
rec_printer p(rec, offsets);
- DBUG_PRINT("ib_cur", ("delete-mark clust %s (%llu) by %lu: %s",
+ DBUG_PRINT("ib_cur", ("delete-mark clust %s (" IB_ID_FMT ") by " IB_ID_FMT ": %s",
index->table_name, index->id,
trx_get_id_for_print(trx),
p.str().c_str()));
@@ -5154,7 +5114,7 @@ btr_cur_del_mark_set_sec_rec(
== dict_table_is_comp(cursor->index->table));
DBUG_PRINT("ib_cur", ("delete-mark=%u sec %u:%u:%u in %s("
- UINT32PF ") by " TRX_ID_FMT,
+ IB_ID_FMT ") by " TRX_ID_FMT,
unsigned(val),
block->page.id.space(), block->page.id.page_no(),
unsigned(page_rec_get_heap_no(rec)),
@@ -5231,10 +5191,15 @@ btr_cur_compress_if_useful(
if (dict_index_is_spatial(cursor->index)) {
const page_t* page = btr_cur_get_page(cursor);
+ const trx_t* trx = NULL;
+
+ if (cursor->rtr_info->thr != NULL) {
+ trx = thr_get_trx(cursor->rtr_info->thr);
+ }
/* Check whether page lock prevents the compression */
- if (!lock_test_prdt_page_lock(
- page_get_space_id(page), page_get_page_no(page))) {
+ if (!lock_test_prdt_page_lock(trx, page_get_space_id(page),
+ page_get_page_no(page))) {
return(false);
}
}
@@ -5840,7 +5805,6 @@ btr_estimate_n_rows_in_range_low(
table_n_rows = dict_table_get_n_rows(index->table);
- mtr_start(&mtr);
/* Below we dive to the two records specified by tuple1 and tuple2 and
we remember the entire dive paths from the tree root. The place where
the tuple1 path ends on the leaf level we call "left border" of our
@@ -5850,6 +5814,7 @@ btr_estimate_n_rows_in_range_low(
example if "5 < x AND x <= 10" then we should not include the left
boundary, but should include the right one. */
+ mtr_start(&mtr);
cursor.path_arr = path1;
@@ -6910,6 +6875,8 @@ struct btr_blob_log_check_t {
log_free_check();
+ DEBUG_SYNC_C("blob_write_middle_after_check");
+
const mtr_log_t log_mode = m_mtr->get_log_mode();
m_mtr->start();
m_mtr->set_log_mode(log_mode);
@@ -7065,10 +7032,7 @@ btr_store_big_rec_extern_fields(
}
#endif /* UNIV_DEBUG || UNIV_BLOB_LIGHT_DEBUG */
- /* Calculate the total number of pages for blob data */
- ulint total_blob_pages = 0;
const page_size_t page_size(dict_table_page_size(index->table));
- const ulint pages_in_extent = dict_table_extent_size(index->table);
/* Space available in compressed page to carry blob data */
const ulint payload_size_zip = page_size.physical()
@@ -7078,55 +7042,6 @@ btr_store_big_rec_extern_fields(
const ulint payload_size = page_size.physical()
- FIL_PAGE_DATA - BTR_BLOB_HDR_SIZE - FIL_PAGE_DATA_END;
- if (page_size.is_compressed()) {
- for (ulint i = 0; i < big_rec_vec->n_fields; i++) {
- total_blob_pages
- += static_cast<ulint>
- (compressBound(static_cast<uLong>
- (big_rec_vec->fields[i].len))
- + payload_size_zip - 1)
- / payload_size_zip;
- }
- } else {
- for (ulint i = 0; i < big_rec_vec->n_fields; i++) {
- total_blob_pages += (big_rec_vec->fields[i].len
- + payload_size - 1)
- / payload_size;
- }
- }
-
- const ulint n_extents = (total_blob_pages + pages_in_extent - 1)
- / pages_in_extent;
- ulint n_reserved = 0;
-#ifdef UNIV_DEBUG
- ulint n_used = 0; /* number of pages used */
-#endif /* UNIV_DEBUG */
-
- if (op == BTR_STORE_INSERT_BULK) {
- mtr_t alloc_mtr;
-
- mtr_start(&alloc_mtr);
- alloc_mtr.set_named_space(index->space);
-
- if (!fsp_reserve_free_extents(&n_reserved, space_id, n_extents,
- FSP_BLOB, &alloc_mtr)) {
- mtr_commit(&alloc_mtr);
- error = DB_OUT_OF_FILE_SPACE;
- goto func_exit;
- }
-
- mtr_commit(&alloc_mtr);
- } else {
- if (!fsp_reserve_free_extents(&n_reserved, space_id, n_extents,
- FSP_BLOB, btr_mtr)) {
- error = DB_OUT_OF_FILE_SPACE;
- goto func_exit;
- }
- }
-
- ut_ad(n_reserved > 0);
- ut_ad(n_reserved == n_extents);
-
/* We have to create a file segment to the tablespace
for each field and put the pointer to the field in rec */
@@ -7160,6 +7075,7 @@ btr_store_big_rec_extern_fields(
buf_block_t* block;
page_t* page;
const ulint commit_freq = 4;
+ ulint r_extents;
ut_ad(page_align(field_ref) == page_align(rec));
@@ -7188,23 +7104,35 @@ btr_store_big_rec_extern_fields(
hint_page_no = prev_page_no + 1;
}
+ mtr_t *alloc_mtr;
+
if (op == BTR_STORE_INSERT_BULK) {
- mtr_t alloc_mtr;
+ mtr_start(&mtr_bulk);
+ mtr_bulk.set_spaces(mtr);
+ alloc_mtr = &mtr_bulk;
+ } else {
+ alloc_mtr = &mtr;
+ }
+
+ if (!fsp_reserve_free_extents(&r_extents, space_id, 1,
+ FSP_BLOB, alloc_mtr,
+ 1)) {
- mtr_start(&alloc_mtr);
- alloc_mtr.set_named_space(index->space);
+ mtr_commit(alloc_mtr);
+ error = DB_OUT_OF_FILE_SPACE;
+ goto func_exit;
+ }
- block = btr_page_alloc(index, hint_page_no,
- FSP_NO_DIR, 0, &alloc_mtr, &mtr);
- mtr_commit(&alloc_mtr);
+ block = btr_page_alloc(index, hint_page_no, FSP_NO_DIR,
+ 0, alloc_mtr, &mtr);
- } else {
- block = btr_page_alloc(index, hint_page_no,
- FSP_NO_DIR, 0, &mtr, &mtr);
+ alloc_mtr->release_free_extents(r_extents);
+
+ if (op == BTR_STORE_INSERT_BULK) {
+ mtr_commit(&mtr_bulk);
}
ut_a(block != NULL);
- ut_ad(++n_used <= (n_reserved * pages_in_extent));
page_no = block->page.id.page_no();
page = buf_block_get_frame(block);
@@ -7443,13 +7371,6 @@ next_zip_page:
rec_offs_make_nth_extern(offsets, field_no);
}
- /* Verify that the number of extents used is the same as the number
- of extents reserved. */
- ut_ad(page_zip != NULL
- || ((n_used + pages_in_extent - 1) / pages_in_extent
- == n_reserved));
- ut_ad((n_used + pages_in_extent - 1) / pages_in_extent <= n_reserved);
-
func_exit:
if (page_zip) {
deflateEnd(&c_stream);
@@ -7459,8 +7380,6 @@ func_exit:
mem_heap_free(heap);
}
- fil_space_release_free_extents(space_id, n_reserved);
-
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/* All pointers to externally stored columns in the record
must be valid. */
@@ -7545,7 +7464,7 @@ btr_free_externally_stored_field(
ulint i, /*!< in: field number of field_ref;
ignored if rec == NULL */
bool rollback, /*!< in: performing rollback? */
- mtr_t* local_mtr MY_ATTRIBUTE((unused))) /*!< in: mtr
+ mtr_t* local_mtr) /*!< in: mtr
containing the latch to data an an
X-latch to the index tree */
{
@@ -7659,7 +7578,7 @@ btr_free_externally_stored_field(
next_page_no = mach_read_from_4(page + FIL_PAGE_NEXT);
btr_page_free_low(index, ext_block, 0,
- true, &mtr);
+ true, &mtr);
if (page_zip != NULL) {
mach_write_to_4(field_ref + BTR_EXTERN_PAGE_NO,
@@ -7686,8 +7605,11 @@ btr_free_externally_stored_field(
page + FIL_PAGE_DATA
+ BTR_BLOB_HDR_NEXT_PAGE_NO);
+ /* We must supply the page level (= 0) as an argument
+ because we did not store it on the page (we save the
+ space overhead from an index page header. */
btr_page_free_low(index, ext_block, 0,
- true, &mtr);
+ true, &mtr);
mlog_write_ulint(field_ref + BTR_EXTERN_PAGE_NO,
next_page_no,
diff --git a/storage/innobase/btr/btr0defragment.cc b/storage/innobase/btr/btr0defragment.cc
index bacc3a4694a..e4202b9bace 100644
--- a/storage/innobase/btr/btr0defragment.cc
+++ b/storage/innobase/btr/btr0defragment.cc
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (C) 2013, 2014 Facebook, Inc. All Rights Reserved.
-Copyright (C) 2014, 2015, MariaDB Corporation. All Rights Reserved.
+Copyright (C) 2014, 2016, MariaDB Corporation. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -33,6 +33,7 @@ Modified 30/07/2014 Jan Lindström jan.lindstrom@mariadb.com
#include "btr0pcur.h"
#include "dict0stats.h"
#include "dict0stats_bg.h"
+#include "dict0defrag_bg.h"
#include "ibuf0ibuf.h"
#include "lock0lock.h"
#include "srv0start.h"
@@ -153,7 +154,7 @@ btr_defragment_init()
{
srv_defragment_interval = ut_microseconds_to_timer(
(ulonglong) (1000000.0 / srv_defragment_frequency));
- mutex_create(LATCH_ID_DEFRAGMENT_MUTEX, &btr_defragment_mutex);
+ mutex_create(LATCH_ID_BTR_DEFRAGMENT_MUTEX, &btr_defragment_mutex);
os_thread_create(btr_defragment_thread, NULL, NULL);
}
@@ -800,6 +801,9 @@ DECLARE_THREAD(btr_defragment_thread)(
cursor = btr_pcur_get_btr_cur(pcur);
index = btr_cur_get_index(cursor);
first_block = btr_cur_get_block(cursor);
+
+ mtr_x_lock(dict_index_get_lock(index), &mtr);
+ mtr.set_named_space(index->space);
last_block = btr_defragment_n_pages(first_block, index,
srv_defragment_n_pages,
&mtr);
@@ -818,16 +822,32 @@ DECLARE_THREAD(btr_defragment_thread)(
/* Update the last_processed time of this index. */
item->last_processed = now;
} else {
+ dberr_t err = DB_SUCCESS;
mtr_commit(&mtr);
/* Reaching the end of the index. */
dict_stats_empty_defrag_stats(index);
- dict_stats_save_defrag_stats(index);
- dict_stats_save_defrag_summary(index);
+ err = dict_stats_save_defrag_stats(index);
+ if (err != DB_SUCCESS) {
+ ib::error() << "Saving defragmentation stats for table "
+ << index->table->name.m_name
+ << " index " << index->name()
+ << " failed with error " << err;
+ } else {
+ err = dict_stats_save_defrag_summary(index);
+
+ if (err != DB_SUCCESS) {
+ ib::error() << "Saving defragmentation summary for table "
+ << index->table->name.m_name
+ << " index " << index->name()
+ << " failed with error " << err;
+ }
+ }
+
btr_defragment_remove_item(item);
}
}
btr_defragment_shutdown();
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
diff --git a/storage/innobase/btr/btr0scrub.cc b/storage/innobase/btr/btr0scrub.cc
index 88ec4f0e538..8ed0117b36e 100644
--- a/storage/innobase/btr/btr0scrub.cc
+++ b/storage/innobase/btr/btr0scrub.cc
@@ -412,7 +412,6 @@ btr_pessimistic_scrub(
}
/* read block variables */
- const ulint space_id = mach_read_from_4(page + FIL_PAGE_SPACE_ID);
const ulint page_no = mach_read_from_4(page + FIL_PAGE_OFFSET);
const page_id_t page_id(dict_index_get_space(index), page_no);
const ulint left_page_no = btr_page_get_prev(page, mtr);
@@ -434,7 +433,7 @@ btr_pessimistic_scrub(
*/
mtr->release_block_at_savepoint(scrub_data->savepoint, block);
- buf_block_t* get_block = btr_block_get(
+ buf_block_t* get_block __attribute__((unused)) = btr_block_get(
lpage_id, page_size,
RW_X_LATCH, index, mtr);
@@ -455,7 +454,7 @@ btr_pessimistic_scrub(
}
if (right_page_no != FIL_NULL) {
- buf_block_t* get_block = btr_block_get(
+ buf_block_t* get_block __attribute__((unused))= btr_block_get(
rpage_id, page_size,
RW_X_LATCH, index, mtr);
}
diff --git a/storage/innobase/btr/btr0sea.cc b/storage/innobase/btr/btr0sea.cc
index 60104b650cd..4489775d46c 100644
--- a/storage/innobase/btr/btr0sea.cc
+++ b/storage/innobase/btr/btr0sea.cc
@@ -52,8 +52,13 @@ char btr_search_enabled = true;
/** Number of adaptive hash index partition. */
ulong btr_ahi_parts = 8;
+#ifdef UNIV_SEARCH_PERF_STAT
+/** Number of successful adaptive hash index lookups */
ulint btr_search_n_succ = 0;
+/** Number of failed adaptive hash index lookups */
ulint btr_search_n_hash_fail = 0;
+#endif /* UNIV_SEARCH_PERF_STAT */
+
/** padding to prevent other memory update
hotspots from residing on the same memory
cache line as btr_search_latches */
@@ -87,7 +92,7 @@ before hash index building is started */
@param[in] n_fields number of complete fields
@param[in] n_bytes number of bytes in an incomplete last field
@return number of complete or incomplete fields */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
ulint
btr_search_get_n_fields(
ulint n_fields,
@@ -99,7 +104,7 @@ btr_search_get_n_fields(
/** Determine the number of accessed key fields.
@param[in] cursor b-tree cursor
@return number of complete or incomplete fields */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
ulint
btr_search_get_n_fields(
const btr_cur_t* cursor)
@@ -561,7 +566,7 @@ ibool
btr_search_update_block_hash_info(
btr_search_t* info,
buf_block_t* block,
- const btr_cur_t* cursor MY_ATTRIBUTE((unused)))
+ const btr_cur_t* cursor)
{
ut_ad(!rw_lock_own(btr_get_search_latch(cursor->index), RW_LOCK_S));
ut_ad(!rw_lock_own(btr_get_search_latch(cursor->index), RW_LOCK_X));
@@ -728,6 +733,10 @@ btr_search_info_update_slow(
if (cursor->flag == BTR_CUR_HASH_FAIL) {
/* Update the hash node reference, if appropriate */
+#ifdef UNIV_SEARCH_PERF_STAT
+ btr_search_n_hash_fail++;
+#endif /* UNIV_SEARCH_PERF_STAT */
+
btr_search_x_lock(cursor->index);
btr_search_update_hash_ref(info, block, cursor);
@@ -1011,7 +1020,7 @@ btr_search_guess_on_hash(
return(FALSE);
}
- buf_block_t* block = buf_block_align(rec);
+ buf_block_t* block = buf_block_from_ahi(rec);
if (!has_search_latch) {
@@ -1114,6 +1123,9 @@ btr_search_guess_on_hash(
#endif
info->last_hash_succ = TRUE;
+#ifdef UNIV_SEARCH_PERF_STAT
+ btr_search_n_succ++;
+#endif
if (!has_search_latch && buf_page_peek_if_too_old(&block->page)) {
buf_page_make_young(&block->page);
@@ -1121,7 +1133,6 @@ btr_search_guess_on_hash(
/* Increment the page get statistics though we did not really
fix the page: for user info only */
-
{
buf_pool_t* buf_pool = buf_pool_from_bpage(&block->page);
@@ -1181,7 +1192,8 @@ retry:
const index_id_t index_id
= btr_page_get_index_id(block->frame);
const ulint ahi_slot
- = ut_fold_ulint_pair(index_id, block->page.id.space())
+ = ut_fold_ulint_pair(static_cast<ulint>(index_id),
+ static_cast<ulint>(block->page.id.space()))
% btr_ahi_parts;
latch = btr_search_latches[ahi_slot];
@@ -2006,7 +2018,7 @@ btr_search_hash_table_validate(ulint hash_table_id)
for (; node != NULL; node = node->next) {
const buf_block_t* block
- = buf_block_align((byte*) node->data);
+ = buf_block_from_ahi((byte*) node->data);
const buf_block_t* hash_block;
buf_pool_t* buf_pool;
index_id_t page_index_id;
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index 04260df18ff..bc4efa4c936 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -72,14 +72,9 @@ Created 11/5/1995 Heikki Tuuri
#include "sync0sync.h"
#include "buf0dump.h"
#include "ut0new.h"
-
#include <new>
#include <map>
#include <sstream>
-#ifdef HAVE_LIBNUMA
-#include <numa.h>
-#include <numaif.h>
-#endif // HAVE_LIBNUMA
#ifndef UNIV_INNOCHECKSUM
#include "fil0pagecompress.h"
#include "fsp0pagecompress.h"
@@ -92,6 +87,48 @@ Created 11/5/1995 Heikki Tuuri
#include "lzo/lzo1x.h"
#endif
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
+#include <numa.h>
+#include <numaif.h>
+struct set_numa_interleave_t
+{
+ set_numa_interleave_t()
+ {
+ if (srv_numa_interleave) {
+
+ ib::info() << "Setting NUMA memory policy to"
+ " MPOL_INTERLEAVE";
+ if (set_mempolicy(MPOL_INTERLEAVE,
+ numa_all_nodes_ptr->maskp,
+ numa_all_nodes_ptr->size) != 0) {
+
+ ib::warn() << "Failed to set NUMA memory"
+ " policy to MPOL_INTERLEAVE: "
+ << strerror(errno);
+ }
+ }
+ }
+
+ ~set_numa_interleave_t()
+ {
+ if (srv_numa_interleave) {
+
+ ib::info() << "Setting NUMA memory policy to"
+ " MPOL_DEFAULT";
+ if (set_mempolicy(MPOL_DEFAULT, NULL, 0) != 0) {
+ ib::warn() << "Failed to set NUMA memory"
+ " policy to MPOL_DEFAULT: "
+ << strerror(errno);
+ }
+ }
+ }
+};
+
+#define NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE set_numa_interleave_t scoped_numa
+#else
+#define NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
+
/*
IMPLEMENTATION OF THE BUFFER POOL
=================================
@@ -323,10 +360,6 @@ The map pointed by this should not be updated */
static buf_pool_chunk_map_t* buf_chunk_map_ref = NULL;
#ifdef UNIV_DEBUG
-/** Protect reference for buf_chunk_map_ref from deleting map,
-because the reference can be caused by debug assertion code. */
-static rw_lock_t* buf_chunk_map_latch;
-
/** Disable resizing buffer pool to make assertion code not expensive. */
my_bool buf_disable_resize_buffer_pool_debug = TRUE;
#endif /* UNIV_DEBUG */
@@ -569,29 +602,31 @@ buf_page_is_zeroes(
}
/** Checks if the page is in crc32 checksum format.
-@param[in] read_buf database page
-@param[in] checksum_field1 new checksum field
-@param[in] checksum_field2 old checksum field
-@param[in] page_no page number of given read_buf
-@param[in] is_log_enabled true if log option is enabled
-@param[in] log_file file pointer to log_file
-@param[in] curr_algo current checksum algorithm
+@param[in] read_buf database page
+@param[in] checksum_field1 new checksum field
+@param[in] checksum_field2 old checksum field
+@param[in] page_no page number of given read_buf
+@param[in] is_log_enabled true if log option is enabled
+@param[in] log_file file pointer to log_file
+@param[in] curr_algo current checksum algorithm
+@param[in] use_legacy_big_endian use legacy big endian algorithm
@return true if the page is in crc32 checksum format. */
UNIV_INLINE
bool
buf_page_is_checksum_valid_crc32(
const byte* read_buf,
ulint checksum_field1,
- ulint checksum_field2
+ ulint checksum_field2,
#ifdef UNIV_INNOCHECKSUM
- ,uintmax_t page_no,
+ uintmax_t page_no,
bool is_log_enabled,
FILE* log_file,
- const srv_checksum_algorithm_t curr_algo
+ const srv_checksum_algorithm_t curr_algo,
#endif /* UNIV_INNOCHECKSUM */
- )
+ bool use_legacy_big_endian)
{
- const uint32_t crc32 = buf_calc_page_crc32(read_buf);
+ const uint32_t crc32 = buf_calc_page_crc32(read_buf,
+ use_legacy_big_endian);
#ifdef UNIV_INNOCHECKSUM
if (is_log_enabled
@@ -740,6 +775,7 @@ buf_page_is_checksum_valid_none(
}
#endif /* UNIV_INNOCHECKSUM */
+
return(checksum_field1 == checksum_field2
&& checksum_field1 == BUF_NO_CHECKSUM_MAGIC);
}
@@ -896,16 +932,18 @@ buf_page_is_corrupted(
const srv_checksum_algorithm_t curr_algo =
static_cast<srv_checksum_algorithm_t>(srv_checksum_algorithm);
+ bool legacy_checksum_checked = false;
+
switch (curr_algo) {
case SRV_CHECKSUM_ALGORITHM_CRC32:
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
if (buf_page_is_checksum_valid_crc32(read_buf,
- checksum_field1, checksum_field2
+ checksum_field1, checksum_field2,
#ifdef UNIV_INNOCHECKSUM
- , page_no, is_log_enabled, log_file, curr_algo
+ page_no, is_log_enabled, log_file, curr_algo,
#endif /* UNIV_INNOCHECKSUM */
- )) {
+ false)) {
return(FALSE);
}
@@ -928,13 +966,13 @@ buf_page_is_corrupted(
if (is_log_enabled) {
fprintf(log_file, "page::%lu;"
- " old style: calculated = %lu;"
- " recorded = %lu\n", page_no,
+ " old style: calculated = " ULINTPF ";"
+ " recorded = " ULINTPF "\n", page_no,
buf_calc_page_old_checksum(read_buf),
checksum_field2);
fprintf(log_file, "page::%lu;"
- " new style: calculated = %lu;"
- " crc32 = %u; recorded = %lu\n",
+ " new style: calculated = " ULINTPF ";"
+ " crc32 = %u; recorded = " ULINTPF "\n",
page_no,
buf_calc_page_new_checksum(read_buf),
buf_calc_page_crc32(read_buf),
@@ -944,6 +982,24 @@ buf_page_is_corrupted(
return(FALSE);
}
+ /* We need to check whether the stored checksum matches legacy
+ big endian checksum or Innodb checksum. We optimize the order
+ based on earlier results. if earlier we have found pages
+ matching legacy big endian checksum, we try to match it first.
+ Otherwise we check innodb checksum first. */
+ if (legacy_big_endian_checksum) {
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2,
+#ifdef UNIV_INNOCHECKSUM
+ page_no, is_log_enabled, log_file, curr_algo,
+#endif /* UNIV_INNOCHECKSUM */
+ true)) {
+
+ return(FALSE);
+ }
+ legacy_checksum_checked = true;
+ }
+
if (buf_page_is_checksum_valid_innodb(read_buf,
checksum_field1, checksum_field2
#ifdef UNIV_INNOCHECKSUM
@@ -961,6 +1017,18 @@ buf_page_is_corrupted(
return(FALSE);
}
+ /* If legacy checksum is not checked, do it now. */
+ if (!legacy_checksum_checked && buf_page_is_checksum_valid_crc32(
+ read_buf, checksum_field1, checksum_field2,
+#ifdef UNIV_INNOCHECKSUM
+ page_no, is_log_enabled, log_file, curr_algo,
+#endif /* UNIV_INNOCHECKSUM */
+ true)) {
+
+ legacy_big_endian_checksum = true;
+ return(FALSE);
+ }
+
#ifdef UNIV_INNOCHECKSUM
if (is_log_enabled) {
fprintf(log_file, "Fail; page %lu"
@@ -1016,12 +1084,19 @@ buf_page_is_corrupted(
return(FALSE);
}
- if (buf_page_is_checksum_valid_crc32(read_buf,
- checksum_field1, checksum_field2
#ifdef UNIV_INNOCHECKSUM
- , page_no, is_log_enabled, log_file, curr_algo)) {
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2,
+ page_no, is_log_enabled, log_file, curr_algo, false)
+ || buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2,
+ page_no, is_log_enabled, log_file, curr_algo, true)) {
#else /* UNIV_INNOCHECKSUM */
- )) {
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2, false)
+ || buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2, true)) {
+
if (curr_algo
== SRV_CHECKSUM_ALGORITHM_STRICT_INNODB) {
page_warn_strict_checksum(
@@ -1054,12 +1129,19 @@ buf_page_is_corrupted(
return(false);
}
- if (buf_page_is_checksum_valid_crc32(read_buf,
- checksum_field1, checksum_field2
#ifdef UNIV_INNOCHECKSUM
- , page_no, is_log_enabled, log_file, curr_algo)) {
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2,
+ page_no, is_log_enabled, log_file, curr_algo, false)
+ || buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2,
+ page_no, is_log_enabled, log_file, curr_algo, true)) {
#else /* UNIV_INNOCHECKSUM */
- )) {
+ if (buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2, false)
+ || buf_page_is_checksum_valid_crc32(read_buf,
+ checksum_field1, checksum_field2, true)) {
+
page_warn_strict_checksum(
curr_algo,
SRV_CHECKSUM_ALGORITHM_CRC32,
@@ -1469,9 +1551,9 @@ buf_chunk_init(
return(NULL);
}
-#ifdef HAVE_LIBNUMA
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
if (srv_numa_interleave) {
- int st = mbind(chunk->mem, mem_size,
+ int st = mbind(chunk->mem, chunk->mem_size(),
MPOL_INTERLEAVE,
numa_all_nodes_ptr->maskp,
numa_all_nodes_ptr->size,
@@ -1482,7 +1564,8 @@ buf_chunk_init(
" (error: " << strerror(errno) << ").";
}
}
-#endif // HAVE_LIBNUMA
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
+
/* Allocate the block descriptors from
the start of the memory block. */
@@ -1891,7 +1974,6 @@ buf_pool_free_instance(
hash_table_free(buf_pool->page_hash);
hash_table_free(buf_pool->zip_hash);
- buf_pool->allocator.~ut_allocator();
/* Free all used temporary slots */
if (buf_pool->tmp_arr) {
for(ulint i = 0; i < buf_pool->tmp_arr->n_slots; i++) {
@@ -1912,11 +1994,13 @@ buf_pool_free_instance(
slot->comp_buf_free = NULL;
}
}
+
+ ut_free(buf_pool->tmp_arr->slots);
+ ut_free(buf_pool->tmp_arr);
+ buf_pool->tmp_arr = NULL;
}
- ut_free(buf_pool->tmp_arr->slots);
- ut_free(buf_pool->tmp_arr);
- buf_pool->tmp_arr = NULL;
+ buf_pool->allocator.~ut_allocator();
}
/********************************************************************//**
@@ -1935,33 +2019,17 @@ buf_pool_init(
ut_ad(n_instances <= MAX_BUFFER_POOLS);
ut_ad(n_instances == srv_buf_pool_instances);
+ NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE;
+
buf_pool_resizing = false;
buf_pool_withdrawing = false;
buf_withdraw_clock = 0;
-#ifdef HAVE_LIBNUMA
- if (srv_numa_interleave) {
- ib::info() << "Setting NUMA memory policy to MPOL_INTERLEAVE";
- if (set_mempolicy(MPOL_INTERLEAVE,
- numa_all_nodes_ptr->maskp,
- numa_all_nodes_ptr->size) != 0) {
- ib::warn() << "Failed to set NUMA memory policy to"
- " MPOL_INTERLEAVE: " << strerror(errno);
- }
- }
-#endif // HAVE_LIBNUMA
-
buf_pool_ptr = (buf_pool_t*) ut_zalloc_nokey(
n_instances * sizeof *buf_pool_ptr);
buf_chunk_map_reg = UT_NEW_NOKEY(buf_pool_chunk_map_t());
- ut_d(buf_chunk_map_latch = static_cast<rw_lock_t*>(
- ut_zalloc_nokey(sizeof(*buf_chunk_map_latch))));
-
- ut_d(rw_lock_create(
- buf_chunk_map_latch_key, buf_chunk_map_latch, SYNC_ANY_LATCH));
-
for (i = 0; i < n_instances; i++) {
buf_pool_t* ptr = &buf_pool_ptr[i];
@@ -1981,18 +2049,6 @@ buf_pool_init(
btr_search_sys_create(buf_pool_get_curr_size() / sizeof(void*) / 64);
-#ifdef HAVE_LIBNUMA
- if (srv_numa_interleave) {
- ib::info() << "Setting NUMA memory policy to MPOL_DEFAULT";
- if (set_mempolicy(MPOL_DEFAULT, NULL, 0) != 0) {
- ib::warn() << "Failed to set NUMA memory policy to"
- " MPOL_DEFAULT: " << strerror(errno);
- }
- }
-#endif // HAVE_LIBNUMA
-
- buf_flush_event = os_event_create(0);
-
return(DB_SUCCESS);
}
@@ -2008,10 +2064,6 @@ buf_pool_free(
buf_pool_free_instance(buf_pool_from_array(i));
}
- ut_d(rw_lock_free(buf_chunk_map_latch));
- ut_d(ut_free(buf_chunk_map_latch));
- ut_d(buf_chunk_map_latch = NULL);
-
UT_DELETE(buf_chunk_map_reg);
buf_chunk_map_reg = buf_chunk_map_ref = NULL;
@@ -2561,6 +2613,8 @@ buf_pool_resize()
ulint new_instance_size;
bool warning = false;
+ NUMA_MEMPOLICY_INTERLEAVE_IN_SCOPE;
+
ut_ad(!buf_pool_resizing);
ut_ad(!buf_pool_withdrawing);
ut_ad(srv_buf_pool_chunk_unit > 0);
@@ -2958,9 +3012,7 @@ calc_buf_pool_size:
}
}
- ut_d(rw_lock_x_lock(buf_chunk_map_latch));
UT_DELETE(chunk_map_old);
- ut_d(rw_lock_x_unlock(buf_chunk_map_latch));
buf_pool_resizing = false;
@@ -3028,14 +3080,12 @@ when waked up either performs a resizing and sleeps again.
extern "C"
os_thread_ret_t
DECLARE_THREAD(buf_resize_thread)(
- void* arg __attribute__((unused)))
+ void* arg MY_ATTRIBUTE((unused)))
{
my_thread_init();
srv_buf_resize_thread_active = true;
- buf_resize_status("not started");
-
while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
os_event_wait(srv_buf_resize_event);
os_event_reset(srv_buf_resize_event);
@@ -3063,7 +3113,7 @@ DECLARE_THREAD(buf_resize_thread)(
srv_buf_resize_thread_active = false;
my_thread_end();
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -3666,6 +3716,7 @@ buf_page_get_zip(
ibool discard_attempted = FALSE;
ibool must_read;
buf_pool_t* buf_pool = buf_pool_get(page_id);
+ buf_page_t* rpage = NULL;
buf_pool->stat.n_page_gets++;
@@ -3684,7 +3735,7 @@ lookup:
/* Page not in buf_pool: needs to be read from file */
ut_ad(!hash_lock);
- buf_read_page(page_id, page_size, NULL);
+ buf_read_page(page_id, page_size, &rpage);
#if defined UNIV_DEBUG || defined UNIV_BUF_DEBUG
ut_a(++buf_dbg_counter % 5771 || buf_validate());
@@ -3873,150 +3924,44 @@ buf_zip_decompress(
}
#ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Gets the block to whose frame the pointer is pointing to.
+/** Get a buffer block from an adaptive hash index pointer.
+This function does not return if the block is not identified.
+@param[in] ptr pointer to within a page frame
@return pointer to block, never NULL */
buf_block_t*
-buf_block_align(
-/*============*/
- const byte* ptr) /*!< in: pointer to a frame */
+buf_block_from_ahi(const byte* ptr)
{
buf_pool_chunk_map_t::iterator it;
- ut_ad(srv_buf_pool_chunk_unit > 0);
-
- /* TODO: This might be still optimistic treatment.
- buf_pool_resize() needs all buf_pool_mutex and all
- buf_pool->page_hash x-latched until actual modification.
- It should block the other user threads and should take while
- which is enough to done the buf_pool_chunk_map access. */
- while (buf_pool_resizing) {
- /* buf_pool_chunk_map is being modified */
- os_thread_sleep(100000); /* 0.1 sec */
- }
-
- ulint counter = 0;
-retry:
-#ifdef UNIV_DEBUG
- bool resize_disabled = (buf_disable_resize_buffer_pool_debug != FALSE);
- if (!resize_disabled) {
- rw_lock_s_lock(buf_chunk_map_latch);
- }
-#endif /* UNIV_DEBUG */
buf_pool_chunk_map_t* chunk_map = buf_chunk_map_ref;
+ ut_ad(buf_chunk_map_ref == buf_chunk_map_reg);
+ ut_ad(!buf_pool_resizing);
- if (ptr < reinterpret_cast<byte*>(srv_buf_pool_chunk_unit)) {
- it = chunk_map->upper_bound(0);
- } else {
- it = chunk_map->upper_bound(
- ptr - srv_buf_pool_chunk_unit);
- }
+ const byte* bound = reinterpret_cast<uintptr_t>(ptr)
+ > srv_buf_pool_chunk_unit
+ ? ptr - srv_buf_pool_chunk_unit : 0;
+ it = chunk_map->upper_bound(bound);
- if (it == chunk_map->end()) {
-#ifdef UNIV_DEBUG
- if (!resize_disabled) {
- rw_lock_s_unlock(buf_chunk_map_latch);
- }
-#endif /* UNIV_DEBUG */
- /* The block should always be found. */
- ++counter;
- ut_a(counter < 10);
- os_thread_sleep(100000); /* 0.1 sec */
- goto retry;
- }
+ ut_a(it != chunk_map->end());
buf_chunk_t* chunk = it->second;
-#ifdef UNIV_DEBUG
- if (!resize_disabled) {
- rw_lock_s_unlock(buf_chunk_map_latch);
- }
-#endif /* UNIV_DEBUG */
-
ulint offs = ptr - chunk->blocks->frame;
offs >>= UNIV_PAGE_SIZE_SHIFT;
- if (offs < chunk->size) {
- buf_block_t* block = &chunk->blocks[offs];
+ ut_a(offs < chunk->size);
- /* The function buf_chunk_init() invokes
- buf_block_init() so that block[n].frame ==
- block->frame + n * UNIV_PAGE_SIZE. Check it. */
- ut_ad(block->frame == page_align(ptr));
-#ifdef UNIV_DEBUG
- /* A thread that updates these fields must
- hold buf_pool->mutex and block->mutex. Acquire
- only the latter. */
- buf_page_mutex_enter(block);
+ buf_block_t* block = &chunk->blocks[offs];
- switch (buf_block_get_state(block)) {
- case BUF_BLOCK_POOL_WATCH:
- case BUF_BLOCK_ZIP_PAGE:
- case BUF_BLOCK_ZIP_DIRTY:
- /* These types should only be used in
- the compressed buffer pool, whose
- memory is allocated from
- buf_pool->chunks, in UNIV_PAGE_SIZE
- blocks flagged as BUF_BLOCK_MEMORY. */
- ut_error;
- break;
- case BUF_BLOCK_NOT_USED:
- case BUF_BLOCK_READY_FOR_USE:
- case BUF_BLOCK_MEMORY:
- /* Some data structures contain
- "guess" pointers to file pages. The
- file pages may have been freed and
- reused. Do not complain. */
- break;
- case BUF_BLOCK_REMOVE_HASH:
- /* buf_LRU_block_remove_hashed_page()
- will overwrite the FIL_PAGE_OFFSET and
- FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID with
- 0xff and set the state to
- BUF_BLOCK_REMOVE_HASH. */
-# ifndef UNIV_DEBUG_VALGRIND
- /* In buf_LRU_block_remove_hashed() we
- explicitly set those values to 0xff and
- declare them uninitialized with
- UNIV_MEM_INVALID() after that. */
- ut_ad(page_get_space_id(page_align(ptr))
- == 0xffffffff);
- ut_ad(page_get_page_no(page_align(ptr))
- == 0xffffffff);
-# endif /* UNIV_DEBUG_VALGRIND */
- break;
- case BUF_BLOCK_FILE_PAGE:
- const ulint space_id1 = block->page.id.space();
- const ulint page_no1 = block->page.id.page_no();
- const ulint space_id2 = page_get_space_id(
- page_align(ptr));
- const ulint page_no2= page_get_page_no(
- page_align(ptr));
-
- if (space_id1 != space_id2 || page_no1 != page_no2) {
-
- ib::error() << "Found a mismatch page,"
- << " expect page "
- << page_id_t(space_id1, page_no1)
- << " but found "
- << page_id_t(space_id2, page_no2);
-
- ut_ad(0);
- }
- break;
- }
-
- buf_page_mutex_exit(block);
-#endif /* UNIV_DEBUG */
-
- return(block);
- }
-
- /* The block should always be found. */
- ++counter;
- ut_a(counter < 10);
- os_thread_sleep(100000); /* 0.1 sec */
- goto retry;
+ /* The function buf_chunk_init() invokes buf_block_init() so that
+ block[n].frame == block->frame + n * UNIV_PAGE_SIZE. Check it. */
+ ut_ad(block->frame == page_align(ptr));
+ /* Read the state of the block without holding a mutex.
+ A state transition from BUF_BLOCK_FILE_PAGE to
+ BUF_BLOCK_REMOVE_HASH is possible during this execution. */
+ ut_d(const buf_page_state state = buf_block_get_state(block));
+ ut_ad(state == BUF_BLOCK_FILE_PAGE || state == BUF_BLOCK_REMOVE_HASH);
+ return(block);
}
/********************************************************************//**
@@ -5657,6 +5602,7 @@ buf_page_create(
/* These 8 bytes are also repurposed for PageIO compression and must
be reset when the frame is assigned to a new page id. See fil0fil.h.
+
FIL_PAGE_FILE_FLUSH_LSN is used on the following pages:
(1) The first page of the InnoDB system tablespace (page 0:0)
(2) FIL_RTREE_SPLIT_SEQ_NUM on R-tree pages .
@@ -5948,7 +5894,7 @@ buf_page_io_complete(
ulint read_page_no;
ulint read_space_id;
byte* frame;
- bool compressed_page;
+ bool compressed_page=false;
ut_ad(bpage->zip.data != NULL || ((buf_block_t*)bpage)->frame != NULL);
@@ -6009,6 +5955,7 @@ buf_page_io_complete(
<< ", should be " << bpage->id;
}
+#ifdef MYSQL_COMPRESSION
compressed_page = Compression::is_compressed_page(frame);
/* If the decompress failed then the most likely case is
@@ -6026,6 +5973,7 @@ buf_page_io_complete(
<< Compression::to_string(meta) << " "
<< "that is not supported by this instance";
}
+#endif /* MYSQL_COMPRESSION */
/* From version 3.23.38 up we store the page checksum
to the 4 first bytes of the page end lsn field */
@@ -6064,7 +6012,7 @@ corrupt:
ib::info()
<< "It is also possible that your"
- " operating system has corrupted"
+ " operating system has corrupted"
" its own file cache and rebooting"
" your computer removes the error."
" If the corrupt page is an index page."
@@ -6125,7 +6073,9 @@ corrupt:
/* If space is being truncated then avoid ibuf operation.
During re-init we have already freed ibuf entries. */
if (uncompressed
+#ifdef MYSQL_COMPRESSION
&& !Compression::is_compressed_page(frame)
+#endif /* MYSQL_COMPRESSION */
&& !recv_no_ibuf_operations
&& !Tablespace::is_undo_tablespace(bpage->id.space())
&& bpage->id.space() != srv_tmp_space.space_id()
@@ -7143,8 +7093,9 @@ buf_print_io_instance(
/* Print some values to help us with visualizing what is
happening with LRU eviction. */
fprintf(file,
- "LRU len: %lu, unzip_LRU len: %lu\n"
- "I/O sum[%lu]:cur[%lu], unzip sum[%lu]:cur[%lu]\n",
+ "LRU len: " ULINTPF ", unzip_LRU len: " ULINTPF "\n"
+ "I/O sum[" ULINTPF "]:cur[" ULINTPF "], "
+ "unzip sum[" ULINTPF "]:cur[" ULINTPF "]\n",
pool_info->lru_len, pool_info->unzip_lru_len,
pool_info->io_sum, pool_info->io_cur,
pool_info->unzip_sum, pool_info->unzip_cur);
@@ -7205,7 +7156,7 @@ buf_print_io(
"----------------------\n", file);
for (i = 0; i < srv_buf_pool_instances; i++) {
- fprintf(file, "---BUFFER POOL %lu\n", i);
+ fprintf(file, "---BUFFER POOL " ULINTPF "\n", i);
buf_print_io_instance(&pool_info[i], file);
}
}
@@ -7683,3 +7634,4 @@ buf_page_decrypt_after_read(
return (success);
}
#endif /* !UNIV_INNOCHECKSUM */
+
diff --git a/storage/innobase/buf/buf0checksum.cc b/storage/innobase/buf/buf0checksum.cc
index 935c8a7ceee..94eafec0584 100644
--- a/storage/innobase/buf/buf0checksum.cc
+++ b/storage/innobase/buf/buf0checksum.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -30,9 +30,9 @@ Created Aug 11, 2011 Vasil Dimov
#include "buf0checksum.h"
#ifndef UNIV_INNOCHECKSUM
-
#include "srv0srv.h"
#endif /* !UNIV_INNOCHECKSUM */
+
#include "buf0types.h"
/** the macro MYSQL_SYSVAR_ENUM() requires "long unsigned int" and if we
@@ -41,6 +41,8 @@ ha_innodb.cc:12251: error: cannot convert 'srv_checksum_algorithm_t*' to
'long unsigned int*' in initialization */
ulong srv_checksum_algorithm = SRV_CHECKSUM_ALGORITHM_INNODB;
+/** set if we have found pages matching legacy big endian checksum */
+bool legacy_big_endian_checksum = false;
/** Calculates the CRC32 checksum of a page. The value is stored to the page
when it is written to a file and also checked for a match when reading from
the file. When reading we allow both normal CRC32 and CRC-legacy-big-endian
diff --git a/storage/innobase/buf/buf0dblwr.cc b/storage/innobase/buf/buf0dblwr.cc
index 64ecb54be63..ff1d2057e6a 100644
--- a/storage/innobase/buf/buf0dblwr.cc
+++ b/storage/innobase/buf/buf0dblwr.cc
@@ -173,7 +173,7 @@ buf_dblwr_init(
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page.
@return true if successful, false if not. */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
bool
buf_dblwr_create(void)
/*==================*/
@@ -576,7 +576,7 @@ buf_dblwr_process(void)
MLOG_TRUNCATE record in redo. */
bool skip_warning =
srv_is_tablespace_truncated(space_id)
- || srv_was_tablespace_truncated(space_id);
+ || srv_was_tablespace_truncated(space);
if (!skip_warning) {
ib::warn() << "Page " << page_no_dblwr
@@ -602,6 +602,14 @@ buf_dblwr_process(void)
page_id, page_size,
0, page_size.physical(), read_buf, NULL, NULL);
+ if (err != DB_SUCCESS) {
+
+ ib::warn()
+ << "Double write buffer recovery: "
+ << page_id << " read failed with "
+ << "error: " << ut_strerr(err);
+ }
+
/* Is page compressed ? */
is_compressed = fil_page_is_compressed_encrypted(read_buf) |
fil_page_is_compressed(read_buf);
@@ -1187,6 +1195,7 @@ try_again:
} else {
ut_a(buf_page_get_state(bpage) == BUF_BLOCK_FILE_PAGE);
+
UNIV_MEM_ASSERT_RW(frame,
bpage->size.logical());
diff --git a/storage/innobase/buf/buf0dump.cc b/storage/innobase/buf/buf0dump.cc
index 831dd13e172..ede7b02ab81 100644
--- a/storage/innobase/buf/buf0dump.cc
+++ b/storage/innobase/buf/buf0dump.cc
@@ -184,6 +184,25 @@ buf_load_status(
va_end(ap);
}
+/** Returns the directory path where the buffer pool dump file will be created.
+@return directory path */
+static
+const char*
+get_buf_dump_dir()
+{
+ const char* dump_dir;
+
+ /* The dump file should be created in the default data directory if
+ innodb_data_home_dir is set as an empty string. */
+ if (strcmp(srv_data_home, "") == 0) {
+ dump_dir = fil_path_to_mysql_datadir;
+ } else {
+ dump_dir = srv_data_home;
+ }
+
+ return(dump_dir);
+}
+
/** Generate the path to the buffer pool dump/load file.
@param[out] path generated path
@param[in] path_size size of 'path', used as in snprintf(3). */
@@ -195,7 +214,7 @@ buf_dump_generate_path(
{
char buf[FN_REFLEN];
- ut_snprintf(buf, sizeof(buf), "%s%c%s", srv_data_home,
+ ut_snprintf(buf, sizeof(buf), "%s%c%s", get_buf_dump_dir(),
OS_PATH_SEPARATOR, srv_buf_dump_filename);
os_file_type_t type;
@@ -217,7 +236,7 @@ buf_dump_generate_path(
and append srv_buf_dump_filename to it. */
char srv_data_home_full[FN_REFLEN];
- my_realpath(srv_data_home_full, srv_data_home, 0);
+ my_realpath(srv_data_home_full, get_buf_dump_dir(), 0);
if (srv_data_home_full[strlen(srv_data_home_full) - 1]
== OS_PATH_SEPARATOR) {
@@ -549,13 +568,22 @@ buf_load()
dump_n = total_buffer_pools_pages;
}
- dump = static_cast<buf_dump_t*>(ut_malloc_nokey(dump_n
- * sizeof(*dump)));
+ if(dump_n != 0) {
+ dump = static_cast<buf_dump_t*>(ut_malloc_nokey(
+ dump_n * sizeof(*dump)));
+ } else {
+ fclose(f);
+ ut_sprintf_timestamp(now);
+ buf_load_status(STATUS_INFO,
+ "Buffer pool(s) load completed at %s"
+ " (%s was empty)", now, full_filename);
+ return;
+ }
if (dump == NULL) {
fclose(f);
buf_load_status(STATUS_ERR,
- "Cannot allocate " ULINTPF " bytes: %s",
+ "Cannot allocate %lu bytes: %s",
(ulint) (dump_n * sizeof(*dump)),
strerror(errno));
return;
@@ -767,8 +795,8 @@ DECLARE_THREAD(buf_dump_thread)(
srv_buf_dump_thread_active = TRUE;
- buf_dump_status(STATUS_VERBOSE, "not started");
- buf_load_status(STATUS_VERBOSE, "not started");
+ buf_dump_status(STATUS_VERBOSE, "Dumping of buffer pool not started");
+ buf_load_status(STATUS_VERBOSE, "Loading of buffer pool not started");
if (srv_buffer_pool_load_at_startup) {
buf_load();
@@ -800,7 +828,7 @@ DECLARE_THREAD(buf_dump_thread)(
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
diff --git a/storage/innobase/buf/buf0flu.cc b/storage/innobase/buf/buf0flu.cc
index 227c71c5cfd..8c7c9f6bdea 100644
--- a/storage/innobase/buf/buf0flu.cc
+++ b/storage/innobase/buf/buf0flu.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2016, Oracle and/or its affiliates
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2016, MariaDB Corporation
Copyright (c) 2013, 2014, Fusion-io
@@ -27,6 +27,7 @@ Created 11/11/1995 Heikki Tuuri
#include "ha_prototypes.h"
#include <mysql/service_thd_wait.h>
+#include <my_dbug.h>
#include "buf0flu.h"
@@ -86,6 +87,7 @@ static lsn_t lsn_avg_rate = 0;
/** Target oldest LSN for the requested flush_sync */
static lsn_t buf_flush_sync_lsn = 0;
+
#ifdef UNIV_PFS_THREAD
mysql_pfs_key_t page_cleaner_thread_key;
#endif /* UNIV_PFS_THREAD */
@@ -180,10 +182,20 @@ struct page_cleaner_t {
page_cleaner_slot_t* slots; /*!< pointer to the slots */
bool is_running; /*!< false if attempt
to shutdown */
+
+#ifdef UNIV_DEBUG
+ ulint n_disabled_debug;
+ /*<! how many of pc threads
+ have been disabled */
+#endif /* UNIV_DEBUG */
};
static page_cleaner_t* page_cleaner = NULL;
+#ifdef UNIV_DEBUG
+my_bool innodb_page_cleaner_disabled_debug;
+#endif /* UNIV_DEBUG */
+
/** If LRU list of a buf_pool is less than this size then LRU eviction
should not happen. This is because when we do LRU flushing we also put
the blocks on free list. If LRU list is very small then we can end up
@@ -998,7 +1010,7 @@ buf_flush_write_block_low(
bool sync) /*!< in: true if sync IO request */
{
page_t* frame = NULL;
- ulint space_id = bpage->id.space();
+ ulint space_id = bpage->id.space();
atomic_writes_t awrites = fil_space_get_atomic_writes(space_id);
#ifdef UNIV_DEBUG
@@ -1603,7 +1615,7 @@ The calling thread is not allowed to own any latches on pages!
It attempts to make 'max' blocks available in the free list. Note that
it is a best effort attempt and it is not guaranteed that after a call
to this function there will be 'max' blocks in the free list.*/
-__attribute__((nonnull))
+
void
buf_flush_LRU_list_batch(
/*=====================*/
@@ -1624,9 +1636,7 @@ buf_flush_LRU_list_batch(
n->flushed = 0;
n->evicted = 0;
n->unzip_LRU_evicted = 0;
-
ut_ad(buf_pool_mutex_own(buf_pool));
-
if (buf_pool->curr_size < buf_pool->old_size
&& buf_pool->withdraw_target > 0) {
withdraw_depth = buf_pool->withdraw_target
@@ -1704,7 +1714,7 @@ buf_flush_LRU_list_batch(
/*******************************************************************//**
Flush and move pages from LRU or unzip_LRU list to the free list.
Whether LRU or unzip_LRU is used depends on the state of the system.*/
-__attribute__((nonnull))
+
static
void
buf_do_LRU_batch(
@@ -1830,7 +1840,7 @@ BUF_FLUSH_LIST, then the caller must not own any latches on pages
not guaranteed that the actual number is that big, though)
@param[in] lsn_limit in the case of BUF_FLUSH_LIST all blocks whose
oldest_modification is smaller than this should be flushed (if their number
-does not exceed min_n), otherwise ignored*/
+does not exceed min_n), otherwise ignored */
void
buf_flush_batch(
buf_pool_t* buf_pool,
@@ -2003,6 +2013,7 @@ buf_flush_wait_batch_end(
}
/** Do flushing batch of a given type.
+NOTE: The calling thread is not allowed to own any latches on pages!
@param[in,out] buf_pool buffer pool instance
@param[in] type flush type
@param[in] min_n wished minimum mumber of blocks flushed
@@ -2010,7 +2021,7 @@ buf_flush_wait_batch_end(
@param[in] lsn_limit in the case BUF_FLUSH_LIST all blocks whose
oldest_modification is smaller than this should be flushed (if their number
does not exceed min_n), otherwise ignored
-@param[out] n the number of pages which were processed is
+@param[out] n_processed the number of pages which were processed is
passed back to caller. Ignored if NULL
@retval true if a batch was queued successfully.
@retval false if another batch of same type was already running. */
@@ -2038,7 +2049,6 @@ buf_flush_do_batch(
return(true);
}
-
/**
Waits until a flush batch of the given lsn ends
@param[in] new_oldest target oldest_modified_lsn to wait for */
@@ -2136,6 +2146,7 @@ buf_flush_lists(
buf_pool_t* buf_pool;
flush_counters_t n;
+ memset(&n, 0, sizeof(flush_counters_t));
buf_pool = buf_pool_from_array(i);
if (!buf_flush_do_batch(buf_pool,
@@ -2237,10 +2248,8 @@ buf_flush_single_page_from_LRU(
} else {
mutex_exit(block_mutex);
}
-
ut_ad(!mutex_own(block_mutex));
}
-
if (!freed) {
/* Can't find a single flushable page. */
ut_ad(!bpage);
@@ -2255,6 +2264,8 @@ buf_flush_single_page_from_LRU(
scanned);
}
+
+
ut_ad(!buf_pool_mutex_own(buf_pool));
return(freed);
}
@@ -2283,12 +2294,10 @@ buf_flush_LRU_list(
}
ut_ad(buf_pool);
-
/* srv_LRU_scan_depth can be arbitrarily large value.
We cap it with current LRU size. */
buf_pool_mutex_enter(buf_pool);
scan_depth = UT_LIST_GET_LEN(buf_pool->LRU);
-
if (buf_pool->curr_size < buf_pool->old_size
&& buf_pool->withdraw_target > 0) {
withdraw_depth = buf_pool->withdraw_target
@@ -2296,16 +2305,13 @@ buf_flush_LRU_list(
} else {
withdraw_depth = 0;
}
-
buf_pool_mutex_exit(buf_pool);
-
if (withdraw_depth > srv_LRU_scan_depth) {
scan_depth = ut_min(withdraw_depth, scan_depth);
} else {
scan_depth = ut_min(static_cast<ulint>(srv_LRU_scan_depth),
scan_depth);
}
-
/* Currently one of page_cleaners is the only thread
that can trigger an LRU flush at the same time.
So, it is not possible that a batch triggered during
@@ -2328,6 +2334,7 @@ buf_flush_LRU_lists(void)
{
ulint n_flushed = 0;
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
+
n_flushed += buf_flush_LRU_list(buf_pool_from_array(i));
}
@@ -2718,8 +2725,6 @@ pc_sleep_if_needed(
return(OS_SYNC_TIME_EXCEEDED);
}
-
-
/******************************************************************//**
Initialize page_cleaner. */
void
@@ -2742,6 +2747,8 @@ buf_flush_page_cleaner_init(void)
ut_zalloc_nokey(page_cleaner->n_slots
* sizeof(*page_cleaner->slots)));
+ ut_d(page_cleaner->n_disabled_debug = 0);
+
page_cleaner->is_running = true;
}
@@ -2997,6 +3004,122 @@ buf_flush_page_cleaner_set_priority(
}
#endif /* UNIV_LINUX */
+#ifdef UNIV_DEBUG
+/** Loop used to disable page cleaner threads. */
+static
+void
+buf_flush_page_cleaner_disabled_loop(void)
+{
+ ut_ad(page_cleaner != NULL);
+
+ if (!innodb_page_cleaner_disabled_debug) {
+ /* We return to avoid entering and exiting mutex. */
+ return;
+ }
+
+ mutex_enter(&page_cleaner->mutex);
+ page_cleaner->n_disabled_debug++;
+ mutex_exit(&page_cleaner->mutex);
+
+ while (innodb_page_cleaner_disabled_debug
+ && srv_shutdown_state == SRV_SHUTDOWN_NONE
+ && page_cleaner->is_running) {
+
+ os_thread_sleep(100000); /* [A] */
+ }
+
+ /* We need to wait for threads exiting here, otherwise we would
+ encounter problem when we quickly perform following steps:
+ 1) SET GLOBAL innodb_page_cleaner_disabled_debug = 1;
+ 2) SET GLOBAL innodb_page_cleaner_disabled_debug = 0;
+ 3) SET GLOBAL innodb_page_cleaner_disabled_debug = 1;
+ That's because after step 1 this thread could still be sleeping
+ inside the loop above at [A] and steps 2, 3 could happen before
+ this thread wakes up from [A]. In such case this thread would
+ not re-increment n_disabled_debug and we would be waiting for
+ him forever in buf_flush_page_cleaner_disabled_debug_update(...).
+
+ Therefore we are waiting in step 2 for this thread exiting here. */
+
+ mutex_enter(&page_cleaner->mutex);
+ page_cleaner->n_disabled_debug--;
+ mutex_exit(&page_cleaner->mutex);
+}
+
+/** Disables page cleaner threads (coordinator and workers).
+It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0).
+@param[in] thd thread handle
+@param[in] var pointer to system variable
+@param[out] var_ptr where the formal string goes
+@param[in] save immediate result from check function */
+void
+buf_flush_page_cleaner_disabled_debug_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save)
+{
+ if (page_cleaner == NULL) {
+ return;
+ }
+
+ if (!*static_cast<const my_bool*>(save)) {
+ if (!innodb_page_cleaner_disabled_debug) {
+ return;
+ }
+
+ innodb_page_cleaner_disabled_debug = false;
+
+ /* Enable page cleaner threads. */
+ while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
+ mutex_enter(&page_cleaner->mutex);
+ const ulint n = page_cleaner->n_disabled_debug;
+ mutex_exit(&page_cleaner->mutex);
+ /* Check if all threads have been enabled, to avoid
+ problem when we decide to re-disable them soon. */
+ if (n == 0) {
+ break;
+ }
+ }
+ return;
+ }
+
+ if (innodb_page_cleaner_disabled_debug) {
+ return;
+ }
+
+ innodb_page_cleaner_disabled_debug = true;
+
+ while (srv_shutdown_state == SRV_SHUTDOWN_NONE) {
+ /* Workers are possibly sleeping on is_requested.
+
+ We have to wake them, otherwise they could possibly
+ have never noticed, that they should be disabled,
+ and we would wait for them here forever.
+
+ That's why we have sleep-loop instead of simply
+ waiting on some disabled_debug_event. */
+ os_event_set(page_cleaner->is_requested);
+
+ mutex_enter(&page_cleaner->mutex);
+
+ ut_ad(page_cleaner->n_disabled_debug
+ <= srv_n_page_cleaners);
+
+ if (page_cleaner->n_disabled_debug
+ == srv_n_page_cleaners) {
+
+ mutex_exit(&page_cleaner->mutex);
+ break;
+ }
+
+ mutex_exit(&page_cleaner->mutex);
+
+ os_thread_sleep(100000);
+ }
+}
+#endif /* UNIV_DEBUG */
+
/******************************************************************//**
page_cleaner thread tasked with flushing dirty pages from the buffer
pools. As of now we'll have only one coordinator.
@@ -3014,6 +3137,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
ulint last_activity = srv_get_activity_count();
ulint last_pages = 0;
+ my_thread_init();
#ifdef UNIV_PFS_THREAD
/* JAN: TODO: MySQL 5.7 PSI
pfs_register_thread(page_cleaner_thread_key);
@@ -3132,6 +3256,7 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
} else {
warn_interval *= 2;
}
+
warn_count = warn_interval;
} else {
--warn_count;
@@ -3268,6 +3393,8 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
/* no activity, but woken up by event */
n_flushed = 0;
}
+
+ ut_d(buf_flush_page_cleaner_disabled_loop());
}
ut_ad(srv_shutdown_state > 0);
@@ -3367,7 +3494,7 @@ thread_exit:
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -3379,10 +3506,12 @@ extern "C"
os_thread_ret_t
DECLARE_THREAD(buf_flush_page_cleaner_worker)(
/*==========================================*/
- void* arg __attribute__((unused)))
+ void* arg MY_ATTRIBUTE((unused)))
/*!< in: a dummy parameter required by
os_thread_create */
{
+ my_thread_init();
+
mutex_enter(&page_cleaner->mutex);
page_cleaner->n_workers++;
mutex_exit(&page_cleaner->mutex);
@@ -3401,6 +3530,8 @@ DECLARE_THREAD(buf_flush_page_cleaner_worker)(
while (true) {
os_event_wait(page_cleaner->is_requested);
+ ut_d(buf_flush_page_cleaner_disabled_loop());
+
if (!page_cleaner->is_running) {
break;
}
@@ -3412,7 +3543,9 @@ DECLARE_THREAD(buf_flush_page_cleaner_worker)(
page_cleaner->n_workers--;
mutex_exit(&page_cleaner->mutex);
- os_thread_exit(NULL);
+ my_thread_end();
+
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -3549,7 +3682,6 @@ buf_flush_validate(
#endif /* UNIV_DEBUG || UNIV_BUF_DEBUG */
#endif /* !UNIV_HOTBACKUP */
-
/******************************************************************//**
Check if there are any dirty pages that belong to a space id in the flush
list in a particular buffer pool.
diff --git a/storage/innobase/buf/buf0lru.cc b/storage/innobase/buf/buf0lru.cc
index 1cb46aecf22..5d2077763a6 100644
--- a/storage/innobase/buf/buf0lru.cc
+++ b/storage/innobase/buf/buf0lru.cc
@@ -145,7 +145,7 @@ If a compressed page is freed other compressed pages may be relocated.
caller needs to free the page to the free list
@retval false if BUF_BLOCK_ZIP_PAGE was removed from page_hash. In
this case the block is already returned to the buddy allocator. */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
buf_LRU_block_remove_hashed(
/*========================*/
@@ -376,7 +376,7 @@ want to hog the CPU and resources. Release the buffer pool and block
mutex and try to force a context switch. Then reacquire the same mutexes.
The current page is "fixed" before the release of the mutexes and then
"unfixed" again once we have reacquired the mutexes. */
-static MY_ATTRIBUTE((nonnull))
+static
void
buf_flush_yield(
/*============*/
@@ -419,7 +419,7 @@ If we have hogged the resources for too long then release the buffer
pool and flush list mutex and do a thread yield. Set the current page
to "sticky" so that it is not relocated during the yield.
@return true if yielded */
-static MY_ATTRIBUTE((nonnull(1), warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
buf_flush_try_yield(
/*================*/
@@ -462,7 +462,7 @@ buf_flush_try_yield(
Removes a single page from a given tablespace inside a specific
buffer pool instance.
@return true if page was removed. */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
buf_flush_or_remove_page(
/*=====================*/
@@ -548,7 +548,7 @@ the list as they age towards the tail of the LRU.
@retval DB_SUCCESS if all freed
@retval DB_FAIL if not all freed
@retval DB_INTERRUPTED if the transaction was interrupted */
-static MY_ATTRIBUTE((nonnull(1), warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
buf_flush_or_remove_pages(
/*======================*/
@@ -668,7 +668,7 @@ Remove or flush all the dirty pages that belong to a given tablespace
inside a specific buffer pool instance. The pages will remain in the LRU
list and will be evicted from the LRU list as they age and move towards
the tail of the LRU list. */
-static MY_ATTRIBUTE((nonnull(1)))
+static
void
buf_flush_dirty_pages(
/*==================*/
@@ -717,7 +717,7 @@ buf_flush_dirty_pages(
/******************************************************************//**
Remove all pages that belong to a given tablespace inside a specific
buffer pool instance when we are DISCARDing the tablespace. */
-static MY_ATTRIBUTE((nonnull))
+static
void
buf_LRU_remove_all_pages(
/*=====================*/
@@ -856,7 +856,7 @@ buffer pool instance when we are deleting the data file(s) of that
tablespace. The pages still remain a part of LRU and are evicted from
the list as they age towards the tail of the LRU only if buf_remove
is BUF_REMOVE_FLUSH_NO_WRITE. */
-static MY_ATTRIBUTE((nonnull(1)))
+static
void
buf_LRU_remove_pages(
/*=================*/
@@ -1902,7 +1902,7 @@ func_exit:
DBUG_PRINT("ib_buf", ("free page %u:%u",
bpage->id.space(), bpage->id.page_no()));
- ut_ad(rw_lock_own(hash_lock, RW_LOCK_X));
+ ut_ad(rw_lock_own(hash_lock, RW_LOCK_X));
ut_ad(buf_page_can_relocate(bpage));
if (!buf_LRU_block_remove_hashed(bpage, zip)) {
@@ -2102,8 +2102,9 @@ buf_LRU_block_free_non_file_page(
case BUF_BLOCK_READY_FOR_USE:
break;
default:
- fprintf(stderr, "InnoDB: Error: Block %p incorrect state %s in buf_LRU_block_free_non_file_page()\n",
- block, buf_get_state_name(block));
+ ib::error() << "Block:" << block
+ << " incorrect state:" << buf_get_state_name(block)
+ << " in buf_LRU_block_free_non_file_page";
return; /* Continue */
}
@@ -2280,27 +2281,27 @@ buf_LRU_block_remove_hashed(
}
hashed_bpage = buf_page_hash_get_low(buf_pool, bpage->id);
-
if (bpage != hashed_bpage) {
ib::error() << "Page " << bpage->id
<< " not found in the hash table";
#ifdef UNIV_DEBUG
- fprintf(stderr,
- "InnoDB: in_page_hash %lu in_zip_hash %lu\n"
- " in_free_list %lu in_flush_list %lu in_LRU_list %lu\n"
- " zip.data %p zip_size %lu page_state %d\n",
- bpage->in_page_hash, bpage->in_zip_hash,
- bpage->in_free_list, bpage->in_flush_list,
- bpage->in_LRU_list, bpage->zip.data,
- bpage->size.logical(),
- buf_page_get_state(bpage));
+
+
+ ib::error()
+ << "in_page_hash:" << bpage->in_page_hash
+ << " in_zip_hash:" << bpage->in_zip_hash
+ // << " in_free_list:"<< bpage->in_fee_list
+ << " in_flush_list:" << bpage->in_flush_list
+ << " in_LRU_list:" << bpage->in_LRU_list
+ << " zip.data:" << bpage->zip.data
+ << " zip_size:" << bpage->size.logical()
+ << " page_state:" << buf_page_get_state(bpage);
#else
- fprintf(stderr,
- "InnoDB: zip.data %p zip_size %lu page_state %d\n",
- bpage->zip.data,
- bpage->size.logical(),
- buf_page_get_state(bpage));
+ ib::error()
+ << " zip.data:" << bpage->zip.data
+ << " zip_size:" << bpage->size.logical()
+ << " page_state:" << buf_page_get_state(bpage);
#endif
if (hashed_bpage) {
@@ -2751,14 +2752,14 @@ buf_LRU_print_instance(
case BUF_BLOCK_FILE_PAGE:
frame = buf_block_get_frame((buf_block_t*) bpage);
fprintf(stderr, "\ntype %lu"
- " index id " UINT32PF "\n",
+ " index id " IB_ID_FMT "\n",
(ulong) fil_page_get_type(frame),
btr_page_get_index_id(frame));
break;
case BUF_BLOCK_ZIP_PAGE:
frame = bpage->zip.data;
fprintf(stderr, "\ntype %lu size %lu"
- " index id " UINT32PF "\n",
+ " index id " IB_ID_FMT "\n",
(ulong) fil_page_get_type(frame),
(ulong) bpage->size.physical(),
btr_page_get_index_id(frame));
diff --git a/storage/innobase/buf/buf0mtflu.cc b/storage/innobase/buf/buf0mtflu.cc
index 06aaac39dd9..117de5cc948 100644
--- a/storage/innobase/buf/buf0mtflu.cc
+++ b/storage/innobase/buf/buf0mtflu.cc
@@ -350,7 +350,7 @@ DECLARE_THREAD(mtflush_io_thread)(
}
}
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
diff --git a/storage/innobase/buf/buf0rea.cc b/storage/innobase/buf/buf0rea.cc
index 5de0412afb2..e96c61d01f9 100644
--- a/storage/innobase/buf/buf0rea.cc
+++ b/storage/innobase/buf/buf0rea.cc
@@ -746,10 +746,10 @@ buf_read_ahead_linear(
if (count) {
DBUG_PRINT("ib_buf", ("linear read-ahead %lu pages, "
- UINT32PF ":" UINT32PF,
+ "%lu:%lu",
count,
- page_id.space(),
- page_id.page_no()));
+ (ulint)page_id.space(),
+ (ulint)page_id.page_no()));
}
/* Read ahead is considered one I/O operation for the purpose of
@@ -773,13 +773,6 @@ buf_read_ibuf_merge_pages(
to get read in, before this
function returns */
const ulint* space_ids, /*!< in: array of space ids */
- const ib_uint64_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
diff --git a/storage/innobase/data/data0data.cc b/storage/innobase/data/data0data.cc
index b4df86963a9..4b788c8952c 100644
--- a/storage/innobase/data/data0data.cc
+++ b/storage/innobase/data/data0data.cc
@@ -447,7 +447,7 @@ print_hex:
fputs(" Hex: ",stderr);
for (i = 0; i < len; i++) {
- fprintf(stderr, "%02lx", (ulint) *data++);
+ fprintf(stderr, "%02lx", static_cast<ulong>(*data++));
}
if (dfield_is_ext(dfield)) {
@@ -837,6 +837,7 @@ dfield_t::clone(
obj->ext = ext;
obj->len = len;
obj->type = type;
+ obj->spatial_status = spatial_status;
if (len != UNIV_SQL_NULL) {
obj->data = obj + 1;
diff --git a/storage/innobase/dict/dict0boot.cc b/storage/innobase/dict/dict0boot.cc
index 4ffcf640a26..5c4e2049723 100644
--- a/storage/innobase/dict/dict0boot.cc
+++ b/storage/innobase/dict/dict0boot.cc
@@ -516,9 +516,9 @@ dict_boot(void)
dict_load_sys_table(dict_sys->sys_indexes);
dict_load_sys_table(dict_sys->sys_fields);
}
+ }
mutex_exit(&dict_sys->mutex);
- }
return(err);
}
diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index 5c7d41a9edb..31952424119 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -494,8 +494,11 @@ dict_build_tablespace_for_table(
/* Determine the tablespace flags. */
bool is_temp = dict_table_is_temporary(table);
+ bool is_encrypted = dict_table_is_encrypted(table);
bool has_data_dir = DICT_TF_HAS_DATA_DIR(table->flags);
- ulint fsp_flags = dict_tf_to_fsp_flags(table->flags, is_temp);
+ ulint fsp_flags = dict_tf_to_fsp_flags(table->flags,
+ is_temp,
+ is_encrypted);
/* Determine the full filepath */
if (is_temp) {
@@ -544,9 +547,14 @@ dict_build_tablespace_for_table(
mtr.set_named_space(table->space);
dict_disable_redo_if_temporary(table, &mtr);
- fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
+ bool ret = fsp_header_init(table->space,
+ FIL_IBD_FILE_INITIAL_SIZE,
+ &mtr);
mtr_commit(&mtr);
+ if (!ret) {
+ return(DB_ERROR);
+ }
} else {
/* We do not need to build a tablespace for this table. It
is already built. Just find the correct tablespace ID. */
@@ -2290,6 +2298,197 @@ dict_create_add_foreign_to_dictionary(
DBUG_RETURN(error);
}
+/** Check whether a column is in an index by the column name
+@param[in] col_name column name for the column to be checked
+@param[in] index the index to be searched
+@return true if this column is in the index, otherwise, false */
+static
+bool
+dict_index_has_col_by_name(
+/*=======================*/
+ const char* col_name,
+ const dict_index_t* index)
+{
+ for (ulint i = 0; i < index->n_fields; i++) {
+ dict_field_t* field = dict_index_get_nth_field(index, i);
+
+ if (strcmp(field->name, col_name) == 0) {
+ return(true);
+ }
+ }
+ return(false);
+}
+
+/** Check whether the foreign constraint could be on a column that is
+part of a virtual index (index contains virtual column) in the table
+@param[in] fk_col_name FK column name to be checked
+@param[in] table the table
+@return true if this column is indexed with other virtual columns */
+bool
+dict_foreign_has_col_in_v_index(
+ const char* fk_col_name,
+ const dict_table_t* table)
+{
+ /* virtual column can't be Primary Key, so start with secondary index */
+ for (dict_index_t* index = dict_table_get_next_index(
+ dict_table_get_first_index(table));
+ index;
+ index = dict_table_get_next_index(index)) {
+
+ if (dict_index_has_virtual(index)) {
+ if (dict_index_has_col_by_name(fk_col_name, index)) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+
+/** Check whether the foreign constraint could be on a column that is
+a base column of some indexed virtual columns.
+@param[in] col_name column name for the column to be checked
+@param[in] table the table
+@return true if this column is a base column, otherwise, false */
+bool
+dict_foreign_has_col_as_base_col(
+ const char* col_name,
+ const dict_table_t* table)
+{
+ /* Loop through each virtual column and check if its base column has
+ the same name as the column name being checked */
+ for (ulint i = 0; i < table->n_v_cols; i++) {
+ dict_v_col_t* v_col = dict_table_get_nth_v_col(table, i);
+
+ /* Only check if the virtual column is indexed */
+ if (!v_col->m_col.ord_part) {
+ continue;
+ }
+
+ for (ulint j = 0; j < v_col->num_base; j++) {
+ if (strcmp(col_name, dict_table_get_col_name(
+ table,
+ v_col->base_col[j]->ind)) == 0) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+/** Check if a foreign constraint is on the given column name.
+@param[in] col_name column name to be searched for fk constraint
+@param[in] table table to which foreign key constraint belongs
+@return true if fk constraint is present on the table, false otherwise. */
+static
+bool
+dict_foreign_base_for_stored(
+ const char* col_name,
+ const dict_table_t* table)
+{
+ /* Loop through each stored column and check if its base column has
+ the same name as the column name being checked */
+ dict_s_col_list::const_iterator it;
+ for (it = table->s_cols->begin();
+ it != table->s_cols->end(); ++it) {
+ dict_s_col_t s_col = *it;
+
+ for (ulint j = 0; j < s_col.num_base; j++) {
+ if (strcmp(col_name, dict_table_get_col_name(
+ table,
+ s_col.base_col[j]->ind)) == 0) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+/** Check if a foreign constraint is on columns served as base columns
+of any stored column. This is to prevent creating SET NULL or CASCADE
+constraint on such columns
+@param[in] local_fk_set set of foreign key objects, to be added to
+the dictionary tables
+@param[in] table table to which the foreign key objects in
+local_fk_set belong to
+@return true if yes, otherwise, false */
+bool
+dict_foreigns_has_s_base_col(
+ const dict_foreign_set& local_fk_set,
+ const dict_table_t* table)
+{
+ dict_foreign_t* foreign;
+
+ if (table->s_cols == NULL) {
+ return (false);
+ }
+
+ for (dict_foreign_set::const_iterator it = local_fk_set.begin();
+ it != local_fk_set.end(); ++it) {
+
+ foreign = *it;
+ ulint type = foreign->type;
+
+ type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
+ | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
+
+ if (type == 0) {
+ continue;
+ }
+
+ for (ulint i = 0; i < foreign->n_fields; i++) {
+ /* Check if the constraint is on a column that
+ is a base column of any stored column */
+ if (dict_foreign_base_for_stored(
+ foreign->foreign_col_names[i], table)) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+/** Check if a column is in foreign constraint with CASCADE properties or
+SET NULL
+@param[in] table table
+@param[in] fk_col_name name for the column to be checked
+@return true if the column is in foreign constraint, otherwise, false */
+bool
+dict_foreigns_has_this_col(
+ const dict_table_t* table,
+ const char* col_name)
+{
+ dict_foreign_t* foreign;
+ const dict_foreign_set* local_fk_set = &table->foreign_set;
+
+ for (dict_foreign_set::const_iterator it = local_fk_set->begin();
+ it != local_fk_set->end();
+ ++it) {
+ foreign = *it;
+ ut_ad(foreign->id != NULL);
+ ulint type = foreign->type;
+
+ type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
+ | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
+
+ if (type == 0) {
+ continue;
+ }
+
+ for (ulint i = 0; i < foreign->n_fields; i++) {
+ if (strcmp(foreign->foreign_col_names[i],
+ col_name) == 0) {
+ return(true);
+ }
+ }
+ }
+ return(false);
+}
+
/** Adds the given set of foreign key objects to the dictionary tables
in the database. This function does not modify the dictionary cache. The
caller must ensure that all foreign key objects contain a valid constraint
diff --git a/storage/innobase/dict/dict0defrag_bg.cc b/storage/innobase/dict/dict0defrag_bg.cc
new file mode 100644
index 00000000000..82aa3abcde6
--- /dev/null
+++ b/storage/innobase/dict/dict0defrag_bg.cc
@@ -0,0 +1,403 @@
+/*****************************************************************************
+
+Copyright (c) 2016, MariaDB Corporation. All Rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file dict/dict0defrag_bg.cc
+Defragmentation routines.
+
+Created 25/08/2016 Jan Lindström
+*******************************************************/
+
+#include "dict0dict.h"
+#include "dict0stats.h"
+#include "dict0stats_bg.h"
+#include "dict0defrag_bg.h"
+#include "row0mysql.h"
+#include "srv0start.h"
+#include "ut0new.h"
+
+#ifdef UNIV_NONINL
+# include "dict0stats_bg.ic"
+#endif
+
+#include <vector>
+
+static ib_mutex_t defrag_pool_mutex;
+
+#ifdef MYSQL_PFS
+static mysql_pfs_key_t defrag_pool_mutex_key;
+#endif
+
+/** The number of tables that can be added to "defrag_pool" before
+it is enlarged */
+static const ulint DEFRAG_POOL_INITIAL_SLOTS = 128;
+
+/** Indices whose defrag stats need to be saved to persistent storage.*/
+struct defrag_pool_item_t {
+ table_id_t table_id;
+ index_id_t index_id;
+};
+
+/** Allocator type, used by std::vector */
+typedef ut_allocator<defrag_pool_item_t>
+ defrag_pool_allocator_t;
+
+/** The multitude of tables to be defragmented- an STL vector */
+typedef std::vector<defrag_pool_item_t, defrag_pool_allocator_t>
+ defrag_pool_t;
+
+/** Iterator type for iterating over the elements of objects of type
+defrag_pool_t. */
+typedef defrag_pool_t::iterator defrag_pool_iterator_t;
+
+/** Pool where we store information on which tables are to be processed
+by background defragmentation. */
+static defrag_pool_t* defrag_pool;
+
+extern bool dict_stats_start_shutdown;
+
+/*****************************************************************//**
+Initialize the defrag pool, called once during thread initialization. */
+void
+dict_defrag_pool_init(void)
+/*=======================*/
+{
+ ut_ad(!srv_read_only_mode);
+ /* JAN: TODO: MySQL 5.7 PSI
+ const PSI_memory_key key2 = mem_key_dict_defrag_pool_t;
+
+ defrag_pool = UT_NEW(defrag_pool_t(defrag_pool_allocator_t(key2)), key2);
+
+ recalc_pool->reserve(RECALC_POOL_INITIAL_SLOTS);
+ */
+ defrag_pool = new std::vector<defrag_pool_item_t, defrag_pool_allocator_t>();
+
+ /* We choose SYNC_STATS_DEFRAG to be below SYNC_FSP_PAGE. */
+ mutex_create(LATCH_ID_DEFRAGMENT_MUTEX, &defrag_pool_mutex);
+}
+
+/*****************************************************************//**
+Free the resources occupied by the defrag pool, called once during
+thread de-initialization. */
+void
+dict_defrag_pool_deinit(void)
+/*=========================*/
+{
+ ut_ad(!srv_read_only_mode);
+
+ defrag_pool->clear();
+ mutex_free(&defrag_pool_mutex);
+
+ UT_DELETE(defrag_pool);
+}
+
+/*****************************************************************//**
+Get an index from the auto defrag pool. The returned index id is removed
+from the pool.
+@return true if the pool was non-empty and "id" was set, false otherwise */
+static
+bool
+dict_stats_defrag_pool_get(
+/*=======================*/
+ table_id_t* table_id, /*!< out: table id, or unmodified if
+ list is empty */
+ index_id_t* index_id) /*!< out: index id, or unmodified if
+ list is empty */
+{
+ ut_ad(!srv_read_only_mode);
+
+ mutex_enter(&defrag_pool_mutex);
+
+ if (defrag_pool->empty()) {
+ mutex_exit(&defrag_pool_mutex);
+ return(false);
+ }
+
+ defrag_pool_item_t& item = defrag_pool->back();
+ *table_id = item.table_id;
+ *index_id = item.index_id;
+
+ defrag_pool->pop_back();
+
+ mutex_exit(&defrag_pool_mutex);
+
+ return(true);
+}
+
+/*****************************************************************//**
+Add an index in a table to the defrag pool, which is processed by the
+background stats gathering thread. Only the table id and index id are
+added to the list, so the table can be closed after being enqueued and
+it will be opened when needed. If the table or index does not exist later
+(has been DROPped), then it will be removed from the pool and skipped. */
+void
+dict_stats_defrag_pool_add(
+/*=======================*/
+ const dict_index_t* index) /*!< in: table to add */
+{
+ defrag_pool_item_t item;
+
+ ut_ad(!srv_read_only_mode);
+
+ mutex_enter(&defrag_pool_mutex);
+
+ /* quit if already in the list */
+ for (defrag_pool_iterator_t iter = defrag_pool->begin();
+ iter != defrag_pool->end();
+ ++iter) {
+ if ((*iter).table_id == index->table->id
+ && (*iter).index_id == index->id) {
+ mutex_exit(&defrag_pool_mutex);
+ return;
+ }
+ }
+
+ item.table_id = index->table->id;
+ item.index_id = index->id;
+ defrag_pool->push_back(item);
+
+ mutex_exit(&defrag_pool_mutex);
+
+ os_event_set(dict_stats_event);
+}
+
+/*****************************************************************//**
+Delete a given index from the auto defrag pool. */
+void
+dict_stats_defrag_pool_del(
+/*=======================*/
+ const dict_table_t* table, /*!<in: if given, remove
+ all entries for the table */
+ const dict_index_t* index) /*!< in: if given, remove this index */
+{
+ ut_a((table && !index) || (!table && index));
+ ut_ad(!srv_read_only_mode);
+ ut_ad(mutex_own(&dict_sys->mutex));
+
+ mutex_enter(&defrag_pool_mutex);
+
+ defrag_pool_iterator_t iter = defrag_pool->begin();
+ while (iter != defrag_pool->end()) {
+ if ((table && (*iter).table_id == table->id)
+ || (index
+ && (*iter).table_id == index->table->id
+ && (*iter).index_id == index->id)) {
+ /* erase() invalidates the iterator */
+ iter = defrag_pool->erase(iter);
+ if (index)
+ break;
+ } else {
+ iter++;
+ }
+ }
+
+ mutex_exit(&defrag_pool_mutex);
+}
+
+/*****************************************************************//**
+Get the first index that has been added for updating persistent defrag
+stats and eventually save its stats. */
+static
+void
+dict_stats_process_entry_from_defrag_pool()
+/*=======================================*/
+{
+ table_id_t table_id;
+ index_id_t index_id;
+ dberr_t err = DB_SUCCESS;
+
+ ut_ad(!srv_read_only_mode);
+
+ /* pop the first index from the auto defrag pool */
+ if (!dict_stats_defrag_pool_get(&table_id, &index_id)) {
+ /* no index in defrag pool */
+ return;
+ }
+
+ dict_table_t* table;
+
+ mutex_enter(&dict_sys->mutex);
+
+ /* If the table is no longer cached, we've already lost the in
+ memory stats so there's nothing really to write to disk. */
+ table = dict_table_open_on_id(table_id, TRUE,
+ DICT_TABLE_OP_OPEN_ONLY_IF_CACHED);
+
+ if (table == NULL) {
+ mutex_exit(&dict_sys->mutex);
+ return;
+ }
+
+ /* Check whether table is corrupted */
+ if (table->corrupted) {
+ dict_table_close(table, TRUE, FALSE);
+ mutex_exit(&dict_sys->mutex);
+ return;
+ }
+ mutex_exit(&dict_sys->mutex);
+
+ dict_index_t* index = dict_table_find_index_on_id(table, index_id);
+
+ if (index == NULL) {
+ return;
+ }
+
+ /* Check whether index is corrupted */
+ if (dict_index_is_corrupted(index)) {
+ dict_table_close(table, FALSE, FALSE);
+ return;
+ }
+
+ err = dict_stats_save_defrag_stats(index);
+
+ if (err != DB_SUCCESS) {
+ ib::error() << "Saving defragmentation status for table "
+ << index->table->name.m_name
+ << " index " << index->name()
+ << " failed " << err;
+ }
+
+ dict_table_close(table, FALSE, FALSE);
+}
+
+/*****************************************************************//**
+Get the first index that has been added for updating persistent defrag
+stats and eventually save its stats. */
+void
+dict_defrag_process_entries_from_defrag_pool()
+/*==========================================*/
+{
+ while (defrag_pool->size() && !dict_stats_start_shutdown) {
+ dict_stats_process_entry_from_defrag_pool();
+ }
+}
+
+/*********************************************************************//**
+Save defragmentation result.
+@return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_summary(
+/*============================*/
+ dict_index_t* index) /*!< in: index */
+{
+ dberr_t ret=DB_SUCCESS;
+ lint now = (lint) ut_time();
+
+ if (dict_index_is_univ(index)) {
+ return DB_SUCCESS;
+ }
+
+ rw_lock_x_lock(dict_operation_lock);
+ mutex_enter(&dict_sys->mutex);
+
+ ret = dict_stats_save_index_stat(index, now, "n_pages_freed",
+ index->stat_defrag_n_pages_freed,
+ NULL,
+ "Number of pages freed during"
+ " last defragmentation run.",
+ NULL);
+
+ mutex_exit(&dict_sys->mutex);
+ rw_lock_x_unlock(dict_operation_lock);
+
+ return (ret);
+}
+
+/*********************************************************************//**
+Save defragmentation stats for a given index.
+@return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_stats(
+/*============================*/
+ dict_index_t* index) /*!< in: index */
+{
+ dberr_t ret;
+
+ if (index->table->ibd_file_missing) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Cannot save defragment stats because "
+ ".ibd file is missing.\n");
+ return (DB_TABLESPACE_DELETED);
+ }
+ if (dict_index_is_corrupted(index)) {
+ ut_print_timestamp(stderr);
+ fprintf(stderr,
+ " InnoDB: Cannot save defragment stats because "
+ "index is corrupted.\n");
+ return(DB_CORRUPTION);
+ }
+
+ if (dict_index_is_univ(index)) {
+ return DB_SUCCESS;
+ }
+
+ lint now = (lint) ut_time();
+ mtr_t mtr;
+ ulint n_leaf_pages;
+ ulint n_leaf_reserved;
+ mtr_start(&mtr);
+ mtr_s_lock(dict_index_get_lock(index), &mtr);
+ n_leaf_reserved = btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES,
+ &n_leaf_pages, &mtr);
+ mtr_commit(&mtr);
+
+ if (n_leaf_reserved == ULINT_UNDEFINED) {
+ // The index name is different during fast index creation,
+ // so the stats won't be associated with the right index
+ // for later use. We just return without saving.
+ return DB_SUCCESS;
+ }
+
+ rw_lock_x_lock(dict_operation_lock);
+
+ mutex_enter(&dict_sys->mutex);
+ ret = dict_stats_save_index_stat(index, now, "n_page_split",
+ index->stat_defrag_n_page_split,
+ NULL,
+ "Number of new page splits on leaves"
+ " since last defragmentation.",
+ NULL);
+ if (ret != DB_SUCCESS) {
+ goto end;
+ }
+
+ ret = dict_stats_save_index_stat(
+ index, now, "n_leaf_pages_defrag",
+ n_leaf_pages,
+ NULL,
+ "Number of leaf pages when this stat is saved to disk",
+ NULL);
+ if (ret != DB_SUCCESS) {
+ goto end;
+ }
+
+ ret = dict_stats_save_index_stat(
+ index, now, "n_leaf_pages_reserved",
+ n_leaf_reserved,
+ NULL,
+ "Number of pages reserved for this index leaves when this stat "
+ "is saved to disk",
+ NULL);
+
+end:
+ mutex_exit(&dict_sys->mutex);
+ rw_lock_x_unlock(dict_operation_lock);
+
+ return (ret);
+}
diff --git a/storage/innobase/dict/dict0dict.cc b/storage/innobase/dict/dict0dict.cc
index 687353cb1b9..6a33de63b69 100644
--- a/storage/innobase/dict/dict0dict.cc
+++ b/storage/innobase/dict/dict0dict.cc
@@ -25,6 +25,9 @@ Data dictionary system
Created 1/8/1996 Heikki Tuuri
***********************************************************************/
+#include <my_config.h>
+#include <string>
+
#include "ha_prototypes.h"
#include <mysqld.h>
#include <strfunc.h>
@@ -33,7 +36,6 @@ Created 1/8/1996 Heikki Tuuri
#include "fts0fts.h"
#include "fil0fil.h"
#include <algorithm>
-#include <string>
#ifdef UNIV_NONINL
#include "dict0dict.ic"
@@ -569,6 +571,8 @@ dict_table_close_and_drop(
trx_t* trx, /*!< in: data dictionary transaction */
dict_table_t* table) /*!< in/out: table */
{
+ dberr_t err = DB_SUCCESS;
+
ut_ad(mutex_own(&dict_sys->mutex));
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
ut_ad(trx->dict_operation != TRX_DICT_OP_NONE);
@@ -583,7 +587,13 @@ dict_table_close_and_drop(
ut_a(!table->stat_initialized);
#endif /* UNIV_DEBUG || UNIV_DDL_DEBUG */
- row_merge_drop_table(trx, table);
+ err = row_merge_drop_table(trx, table);
+
+ if (err != DB_SUCCESS) {
+ ib::error() << "At " << __FILE__ << ":" << __LINE__
+ << " row_merge_drop_table returned error: " << err
+ << " table: " << table->name.m_name;
+ }
}
/** Check if the table has a given (non_virtual) column.
@@ -684,6 +694,7 @@ dict_table_get_col_name_for_mysql(
return(s);
}
+
/** Returns a virtual column's name.
@param[in] table target table
@param[in] col_nr virtual column number (nth virtual column)
@@ -1237,7 +1248,7 @@ dict_init(void)
dict_operation_lock, SYNC_DICT_OPERATION);
if (!srv_read_only_mode) {
- dict_foreign_err_file = os_file_create_tmpfile();
+ dict_foreign_err_file = os_file_create_tmpfile(NULL);
ut_a(dict_foreign_err_file);
}
@@ -1309,9 +1320,7 @@ dict_table_open_on_name(
if (ignore_err == DICT_ERR_IGNORE_NONE
&& table->is_encrypted) {
/* Make life easy for drop table. */
- if (table->can_be_evicted) {
- dict_table_move_from_lru_to_non_lru(table);
- }
+ dict_table_prevent_eviction(table);
if (table->can_be_evicted) {
dict_move_to_mru(table);
@@ -1328,10 +1337,8 @@ dict_table_open_on_name(
/* If table is corrupted, return NULL */
else if (ignore_err == DICT_ERR_IGNORE_NONE
&& table->corrupted) {
-
/* Make life easy for drop table. */
dict_table_prevent_eviction(table);
-
if (!dict_locked) {
mutex_exit(&dict_sys->mutex);
}
@@ -1668,7 +1675,6 @@ dict_table_move_from_lru_to_non_lru(
@param[in] table table instance
@param[in] id index id
@return index or NULL */
-UNIV_INTERN
dict_index_t*
dict_table_find_index_on_id(
const dict_table_t* table,
@@ -1764,6 +1770,7 @@ dict_table_rename_in_cache(
dict_index_t* index;
ulint fold;
char old_name[MAX_FULL_NAME_LEN + 1];
+ os_file_type_t ftype;
ut_ad(mutex_own(&dict_sys->mutex));
@@ -1798,7 +1805,6 @@ dict_table_rename_in_cache(
.ibd file and rebuild the .isl file if needed. */
if (dict_table_is_discarded(table)) {
- os_file_type_t type;
bool exists;
char* filepath;
@@ -1826,7 +1832,7 @@ dict_table_rename_in_cache(
fil_delete_tablespace(table->space, BUF_REMOVE_ALL_NO_WRITE);
/* Delete any temp file hanging around. */
- if (os_file_status(filepath, &exists, &type)
+ if (os_file_status(filepath, &exists, &ftype)
&& exists
&& !os_file_delete_if_exists(innodb_temp_file_key,
filepath, NULL)) {
@@ -1860,19 +1866,31 @@ dict_table_rename_in_cache(
ut_free(old_path);
return(DB_TABLESPACE_EXISTS);
}
+ } else {
+ new_path = fil_make_filepath(
+ NULL, new_name, IBD, false);
+ }
+
+ /* New filepath must not exist. */
+ err = fil_rename_tablespace_check(
+ table->space, old_path, new_path, false);
+ if (err != DB_SUCCESS) {
+ ut_free(old_path);
+ ut_free(new_path);
+ return(err);
}
bool success = fil_rename_tablespace(
table->space, old_path, new_name, new_path);
ut_free(old_path);
+ ut_free(new_path);
/* If the tablespace is remote, a new .isl file was created
- If success, delete the old one. If not, delete the new one. */
- if (new_path) {
-
- ut_free(new_path);
- RemoteDatafile::delete_link_file(success ? old_name : new_name);
+ If success, delete the old one. If not, delete the new one. */
+ if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+ RemoteDatafile::delete_link_file(
+ success ? old_name : new_name);
}
if (!success) {
@@ -2271,6 +2289,12 @@ dict_table_remove_from_cache_low(
trx_free_for_background(trx);
}
+ /* Free virtual column template if any */
+ if (table->vc_templ != NULL) {
+ dict_free_vc_templ(table->vc_templ);
+ UT_DELETE(table->vc_templ);
+ }
+
size = mem_heap_get_size(table->heap) + strlen(table->name.m_name) + 1;
ut_ad(dict_sys->size >= size);
@@ -2516,7 +2540,7 @@ dict_index_too_big_for_tree(
REC_STATUS_ORDINARY records. */
field_max_size = dict_col_get_fixed_size(col, comp);
- if (field_max_size) {
+ if (field_max_size && field->fixed_len != 0) {
/* dict_index_add_col() should guarantee this */
ut_ad(!field->prefix_len
|| field->fixed_len == field->prefix_len);
@@ -2681,18 +2705,31 @@ dict_index_add_to_cache_w_vcol(
}
n_ord = new_index->n_uniq;
-
/* Flag the ordering columns and also set column max_prefix */
for (i = 0; i < n_ord; i++) {
const dict_field_t* field
= dict_index_get_nth_field(new_index, i);
- field->col->ord_part = 1;
-
- if (field->prefix_len > field->col->max_prefix) {
+ /* Check the column being added in the index for
+ the first time and flag the ordering column. */
+ if (field->col->ord_part == 0 ) {
+ field->col->max_prefix = field->prefix_len;
+ field->col->ord_part = 1;
+ } else if (field->prefix_len == 0) {
+ /* Set the max_prefix for a column to 0 if
+ its prefix length is 0 (for this index)
+ even if it was a part of any other index
+ with some prefix length. */
+ field->col->max_prefix = 0;
+ } else if (field->col->max_prefix != 0
+ && field->prefix_len
+ > field->col->max_prefix) {
+ /* Set the max_prefix value based on the
+ prefix_len. */
field->col->max_prefix = field->prefix_len;
}
+ ut_ad(field->col->ord_part == 1);
}
new_index->stat_n_diff_key_vals =
@@ -3051,7 +3088,6 @@ dict_index_add_col(
field = dict_index_get_nth_field(index, index->n_def - 1);
field->col = col;
-
/* DATA_POINT is a special type, whose fixed_len should be:
1) DATA_MBR_LEN, when it's indexed in R-TREE. In this case,
it must be the first col to be added.
@@ -3663,7 +3699,7 @@ dict_foreign_find_index(
/*!< out: column number where
error happened */
dict_index_t** err_index)
- /*!< out: index where error
+ /*!< out: index where error
happened */
{
dict_index_t* index;
@@ -4645,6 +4681,11 @@ dict_foreign_push_index_error(
}
/*********************************************************************//**
+Scans a table create SQL string and adds to the data dictionary the foreign key
+constraints declared in the string. This function should be called after the
+indexes for a table have been created. Each foreign key constraint must be
+accompanied with indexes in bot participating tables. The indexes are allowed
+to contain more fields than mentioned in the constraint.
@return error code or DB_SUCCESS */
static
dberr_t
@@ -4879,6 +4920,10 @@ loop:
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ if (dict_foreigns_has_s_base_col(local_fk_set, table)) {
+ return(DB_NO_FK_ON_S_BASE_COL);
+ }
+
/**********************************************************/
/* The following call adds the foreign key constraints
to the data dictionary system tables on disk */
@@ -4894,6 +4939,8 @@ loop:
local_fk_set.end(),
dict_foreign_add_to_referenced_table());
local_fk_set.clear();
+
+ dict_mem_table_fill_foreign_vcol_set(table);
}
return(error);
}
@@ -4919,53 +4966,52 @@ loop:
}
if (my_isspace(cs, *ptr)) {
- ptr1 = dict_accept(cs, ptr, "IF", &success);
+ ptr1 = dict_accept(cs, ptr, "IF", &success);
- if (success) {
- if (!my_isspace(cs, *ptr1)) {
- goto loop;
- }
- ptr1 = dict_accept(cs, ptr1, "NOT", &success);
- if (!success) {
- goto loop;
- }
- ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
- if (!success) {
- goto loop;
- }
- ptr = ptr1;
- }
+ if (success) {
+ if (!my_isspace(cs, *ptr1)) {
+ goto loop;
+ }
+ ptr1 = dict_accept(cs, ptr1, "NOT", &success);
+ if (!success) {
+ goto loop;
+ }
+ ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
+ if (!success) {
+ goto loop;
+ }
+ ptr = ptr1;
+ }
}
orig = ptr;
ptr = dict_accept(cs, ptr, "(", &success);
if (!success) {
- if (constraint_name) {
- /* MySQL allows also an index id before the '('; we
- skip it */
- ptr = dict_skip_word(cs, ptr, &success);
- if (!success) {
- dict_foreign_report_syntax_err(
- "%s table %s with foreign key constraint"
- " failed. Parse error in '%s'"
- " near '%s'.\n",
- operation, create_name, start_of_latest_foreign, orig);
-
- ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
- "%s table %s with foreign key constraint"
- " failed. Parse error in '%s'"
- " near '%s'.",
- operation, create_name, start_of_latest_foreign, orig);
- return(DB_CANNOT_ADD_CONSTRAINT);
- }
- }
- else {
- while (my_isspace(cs, *ptr)) {
- ptr++;
- }
+ if (constraint_name) {
+ /* MySQL allows also an index id before the '('; we
+ skip it */
+ ptr = dict_skip_word(cs, ptr, &success);
+ if (!success) {
+ dict_foreign_report_syntax_err(
+ "%s table %s with foreign key constraint"
+ " failed. Parse error in '%s'"
+ " near '%s'.\n",
+ operation, create_name, start_of_latest_foreign, orig);
+
+ ib_push_warning(trx, DB_CANNOT_ADD_CONSTRAINT,
+ "%s table %s with foreign key constraint"
+ " failed. Parse error in '%s'"
+ " near '%s'.",
+ operation, create_name, start_of_latest_foreign, orig);
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+ } else {
+ while (my_isspace(cs, *ptr)) {
+ ptr++;
+ }
- ptr = dict_scan_id(cs, ptr, heap,
+ ptr = dict_scan_id(cs, ptr, heap,
&constraint_name, FALSE, FALSE);
}
@@ -5095,6 +5141,23 @@ col_loop1:
return(DB_CANNOT_ADD_CONSTRAINT);
}
+ /* Don't allow foreign keys on partitioned tables yet. */
+ ptr1 = dict_scan_to(ptr, "PARTITION");
+ if (ptr1) {
+ ptr1 = dict_accept(cs, ptr1, "PARTITION", &success);
+ if (success && my_isspace(cs, *ptr1)) {
+ ptr2 = dict_accept(cs, ptr1, "BY", &success);
+ if (success) {
+ my_error(ER_FOREIGN_KEY_ON_PARTITIONED,MYF(0));
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+ }
+ }
+ if (dict_table_is_partition(table)) {
+ my_error(ER_FOREIGN_KEY_ON_PARTITIONED,MYF(0));
+ return(DB_CANNOT_ADD_CONSTRAINT);
+ }
+
/* Let us create a constraint struct */
foreign = dict_mem_foreign_create();
@@ -5602,7 +5665,7 @@ dict_foreign_parse_drop_constraints(
char* str;
size_t len;
const char* ptr;
- const char* ptr1;
+ const char* ptr1;
const char* id;
CHARSET_INFO* cs;
@@ -5656,11 +5719,10 @@ loop:
ptr1 = dict_accept(cs, ptr, "IF", &success);
if (success && my_isspace(cs, *ptr1)) {
- ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
- if (success) {
-
- ptr = ptr1;
- }
+ ptr1 = dict_accept(cs, ptr1, "EXISTS", &success);
+ if (success) {
+ ptr = ptr1;
+ }
}
ptr = dict_scan_id(cs, ptr, heap, &id, FALSE, TRUE);
@@ -5875,6 +5937,12 @@ dict_index_copy_rec_order_prefix(
n = dict_index_get_n_unique_in_tree(index);
} else {
n = dict_index_get_n_unique_in_tree_nonleaf(index);
+ /* For internal node of R-tree, since we need to
+ compare the page no field, so, we need to copy this
+ field as well. */
+ if (dict_index_is_spatial(index)) {
+ n++;
+ }
}
}
@@ -5992,11 +6060,11 @@ dict_print_info_on_foreign_key_in_create_format(
str.append(" CONSTRAINT ");
- str.append(ut_get_name(trx, FALSE, stripped_id));
+ str.append(innobase_quote_identifier(trx, stripped_id));
str.append(" FOREIGN KEY (");
for (i = 0;;) {
- str.append(ut_get_name(trx, FALSE, foreign->foreign_col_names[i]));
+ str.append(innobase_quote_identifier(trx, foreign->foreign_col_names[i]));
if (++i < foreign->n_fields) {
str.append(", ");
@@ -6010,18 +6078,18 @@ dict_print_info_on_foreign_key_in_create_format(
if (dict_tables_have_same_db(foreign->foreign_table_name_lookup,
foreign->referenced_table_name_lookup)) {
/* Do not print the database name of the referenced table */
- str.append(ut_get_name(trx, TRUE,
+ str.append(ut_get_name(trx,
dict_remove_db_name(
foreign->referenced_table_name)));
} else {
- str.append(ut_get_name(trx, TRUE,
+ str.append(ut_get_name(trx,
foreign->referenced_table_name));
}
str.append(" (");
for (i = 0;;) {
- str.append(ut_get_name(trx, FALSE,
+ str.append(innobase_quote_identifier(trx,
foreign->referenced_col_names[i]));
if (++i < foreign->n_fields) {
@@ -6096,12 +6164,12 @@ dict_print_info_on_foreign_keys(
str.append(" ");
}
- str.append(ut_get_name(trx, FALSE,
+ str.append(innobase_quote_identifier(trx,
foreign->foreign_col_names[i]));
}
str.append(") REFER ");
- str.append(ut_get_name(trx, TRUE,
+ str.append(ut_get_name(trx,
foreign->referenced_table_name));
str.append(")");
@@ -6109,8 +6177,8 @@ dict_print_info_on_foreign_keys(
if (i) {
str.append(" ");
}
- str.append(ut_get_name(
- trx, FALSE,
+ str.append(innobase_quote_identifier(
+ trx,
foreign->referenced_col_names[i]));
}
@@ -6143,7 +6211,6 @@ dict_print_info_on_foreign_keys(
}
mutex_exit(&dict_sys->mutex);
-
return str;
}
@@ -6262,6 +6329,13 @@ dict_set_corrupted(
goto func_exit;
}
+ /* If this is read only mode, do not update SYS_INDEXES, just
+ mark it as corrupted in memory */
+ if (srv_read_only_mode) {
+ index->type |= DICT_CORRUPT;
+ goto func_exit;
+ }
+
heap = mem_heap_create(sizeof(dtuple_t) + 2 * (sizeof(dfield_t)
+ sizeof(que_fork_t) + sizeof(upd_node_t)
+ sizeof(upd_t) + 12));
@@ -6451,6 +6525,7 @@ dict_set_merge_threshold_all_debug(
mutex_exit(&dict_sys->mutex);
}
+
#endif /* UNIV_DEBUG */
#endif /* !UNIV_HOTBACKUP */
@@ -6914,7 +6989,8 @@ dict_fs2utf8(
errors = 0;
strconvert(
- &my_charset_filename, buf, (uint) (buf_p - buf), system_charset_info,
+ &my_charset_filename, buf, (uint) (buf_p - buf),
+ system_charset_info,
table_utf8, table_utf8_size,
&errors);
@@ -7380,11 +7456,13 @@ dict_table_t::flags | 0 | 1 | 1 | 1
fil_space_t::flags | 0 | 0 | 1 | 1
@param[in] table_flags dict_table_t::flags
@param[in] is_temp whether the tablespace is temporary
+@param[in] is_encrypted whether the tablespace is encrypted
@return tablespace flags (fil_space_t::flags) */
ulint
dict_tf_to_fsp_flags(
ulint table_flags,
- bool is_temp)
+ bool is_temp,
+ bool is_encrypted)
{
DBUG_EXECUTE_IF("dict_tf_to_fsp_flags_failure",
return(ULINT_UNDEFINED););
@@ -7411,9 +7489,30 @@ dict_tf_to_fsp_flags(
has_data_dir,
is_shared,
is_temp,
- page_compression,
- page_compression_level,
- atomic_writes);
+ 0,
+ 0,
+ 0,
+ is_encrypted);
+
+ /* In addition, tablespace flags also contain if the page
+ compression is used for this table. */
+ if (page_compression) {
+ fsp_flags |= FSP_FLAGS_SET_PAGE_COMPRESSION(fsp_flags, page_compression);
+ }
+
+ /* In addition, tablespace flags also contain page compression level
+ if page compression is used for this table. */
+ if (page_compression && page_compression_level) {
+ fsp_flags |= FSP_FLAGS_SET_PAGE_COMPRESSION_LEVEL(fsp_flags, page_compression_level);
+ }
+
+ /* In addition, tablespace flags also contain flag if atomic writes
+ is used for this table */
+ if (atomic_writes) {
+ fsp_flags |= FSP_FLAGS_SET_ATOMIC_WRITES(fsp_flags, atomic_writes);
+ }
+
+ ut_ad(fsp_flags_is_valid(fsp_flags));
return(fsp_flags);
}
@@ -7442,10 +7541,10 @@ dict_tf_to_row_format_string(
}
/** Look for any dictionary objects that are found in the given tablespace.
-@param[in] space Tablespace ID to search for.
+@param[in] space_id Tablespace ID to search for.
@return true if tablespace is empty. */
bool
-dict_tablespace_is_empty(
+dict_space_is_empty(
ulint space_id)
{
btr_pcur_t pcur;
@@ -7480,6 +7579,55 @@ dict_tablespace_is_empty(
return(!found);
}
+
+/** Find the space_id for the given name in sys_tablespaces.
+@param[in] name Tablespace name to search for.
+@return the tablespace ID. */
+ulint
+dict_space_get_id(
+ const char* name)
+{
+ btr_pcur_t pcur;
+ const rec_t* rec;
+ mtr_t mtr;
+ ulint name_len = strlen(name);
+ ulint id = ULINT_UNDEFINED;
+
+ rw_lock_x_lock(dict_operation_lock);
+ mutex_enter(&dict_sys->mutex);
+ mtr_start(&mtr);
+
+ for (rec = dict_startscan_system(&pcur, &mtr, SYS_TABLESPACES);
+ rec != NULL;
+ rec = dict_getnext_system(&pcur, &mtr)) {
+ const byte* field;
+ ulint len;
+
+ field = rec_get_nth_field_old(
+ rec, DICT_FLD__SYS_TABLESPACES__NAME, &len);
+ ut_ad(len > 0);
+ ut_ad(len < OS_FILE_MAX_PATH);
+
+ if (len == name_len && ut_memcmp(name, field, len) == 0) {
+
+ field = rec_get_nth_field_old(
+ rec, DICT_FLD__SYS_TABLESPACES__SPACE, &len);
+ ut_ad(len == 4);
+ id = mach_read_from_4(field);
+
+ /* This is normally called by dict_getnext_system()
+ at the end of the index. */
+ btr_pcur_close(&pcur);
+ break;
+ }
+ }
+
+ mtr_commit(&mtr);
+ mutex_exit(&dict_sys->mutex);
+ rw_lock_x_unlock(dict_operation_lock);
+
+ return(id);
+}
#endif /* !UNIV_HOTBACKUP */
/** Determine the extent size (in pages) for the given table
diff --git a/storage/innobase/dict/dict0load.cc b/storage/innobase/dict/dict0load.cc
index 5267cf1a199..f38ad85e903 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -733,7 +733,6 @@ err_len:
@param[in] space_id Tablespace ID
@return First filepath (caller must invoke ut_free() on it)
@retval NULL if no SYS_DATAFILES entry was found. */
-static
char*
dict_get_first_path(
ulint space_id)
@@ -819,7 +818,7 @@ dict_get_first_path(
@retval NULL if no dictionary entry was found. */
static
char*
-dict_get_space_name(
+dict_space_get_name(
ulint space_id,
mem_heap_t* callers_heap)
{
@@ -1127,7 +1126,7 @@ dict_sys_tablespaces_rec_read(
rec, DICT_FLD__SYS_TABLESPACES__NAME, &len);
if (len == 0 || len == UNIV_SQL_NULL) {
ib::error() << "Wrong field length in SYS_TABLESPACES.NAME: "
- << len;
+ << len;
return(false);
}
strncpy(name, reinterpret_cast<const char*>(field), NAME_LEN);
@@ -1137,7 +1136,7 @@ dict_sys_tablespaces_rec_read(
rec, DICT_FLD__SYS_TABLESPACES__FLAGS, &len);
if (len != 4) {
ib::error() << "Wrong field length in SYS_TABLESPACES.FLAGS: "
- << len;
+ << len;
return(false);
}
*flags = mach_read_from_4(field);
@@ -1313,32 +1312,16 @@ dict_sys_tables_rec_read(
*flags = dict_sys_tables_type_to_tf(type, *n_cols);
- /* For tables created with old versions of InnoDB, there may be
- garbage in SYS_TABLES.MIX_LEN where flags2 are found. Such tables
- would always be in ROW_FORMAT=REDUNDANT which do not have the
- high bit set in n_cols, and flags would be zero. */
- if (*flags != 0 || *n_cols & DICT_N_COLS_COMPACT) {
-
- /* Get flags2 from SYS_TABLES.MIX_LEN */
- field = rec_get_nth_field_old(
- rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
- *flags2 = mach_read_from_4(field);
-
- if (!dict_tf2_is_valid(*flags, *flags2)) {
- ib::error() << "Table " << table_name << " in InnoDB"
- " data dictionary contains invalid flags."
- " SYS_TABLES.MIX_LEN=" << *flags2;
- *flags2 = ULINT_UNDEFINED;
- return(false);
- }
-
- /* DICT_TF2_FTS will be set when indexes are being loaded */
- *flags2 &= ~DICT_TF2_FTS;
+ /* Get flags2 from SYS_TABLES.MIX_LEN */
+ field = rec_get_nth_field_old(
+ rec, DICT_FLD__SYS_TABLES__MIX_LEN, &len);
+ *flags2 = mach_read_from_4(field);
- /* Now that we have used this bit, unset it. */
- *n_cols &= ~DICT_N_COLS_COMPACT;
- }
+ /* DICT_TF2_FTS will be set when indexes are being loaded */
+ *flags2 &= ~DICT_TF2_FTS;
+ /* Now that we have used this bit, unset it. */
+ *n_cols &= ~DICT_N_COLS_COMPACT;
return(true);
}
@@ -1431,10 +1414,10 @@ dict_check_sys_tables(
and the tablespace_name are the same.
Some hidden tables like FTS AUX tables may not be found in
the dictionary since they can always be found in the default
- location. If so, then dict_get_space_name() will return NULL,
+ location. If so, then dict_space_get_name() will return NULL,
the space name must be the table_name, and the filepath can be
discovered in the default location.*/
- char* shared_space_name = dict_get_space_name(space_id, NULL);
+ char* shared_space_name = dict_space_get_name(space_id, NULL);
space_name = shared_space_name == NULL
? table_name.m_name
: shared_space_name;
@@ -1468,17 +1451,13 @@ dict_check_sys_tables(
opened. */
char* filepath = dict_get_first_path(space_id);
- /* We need to read page 0 to get (optional) IV
- regardless if encryptions is turned on or not,
- since if it's off we should decrypt a potentially
- already encrypted table */
- bool read_page_0 = true;
-
/* Check that the .ibd file exists. */
bool is_temp = flags2 & DICT_TF2_TEMPORARY;
- ulint fsp_flags = dict_tf_to_fsp_flags(flags, is_temp);
-
- validate = true;
+ bool is_encrypted = flags2 & DICT_TF2_ENCRYPTION;
+ ulint fsp_flags = dict_tf_to_fsp_flags(flags,
+ is_temp,
+ is_encrypted);
+ validate = true; /* Encryption */
dberr_t err = fil_ibd_open(
validate,
@@ -2601,7 +2580,7 @@ dict_load_indexes(
dictionary cache for such metadata corruption,
since we would always be able to set it
when loading the dictionary cache */
- ut_ad(index->table == table);
+ index->table = table;
dict_set_corrupted_index_cache_only(index);
ib::info() << "Index is corrupt but forcing"
@@ -2848,7 +2827,7 @@ dict_get_and_save_space_name(
dict_mutex_enter_for_mysql();
}
- table->tablespace = dict_get_space_name(
+ table->tablespace = dict_space_get_name(
table->space, table->heap);
if (!dict_mutex_own) {
@@ -2948,7 +2927,7 @@ dict_load_tablespace(
if (DICT_TF_HAS_SHARED_SPACE(table->flags)) {
if (srv_sys_tablespaces_open) {
shared_space_name =
- dict_get_space_name(table->space, NULL);
+ dict_space_get_name(table->space, NULL);
} else {
/* Make the temporary tablespace name. */
@@ -3012,7 +2991,9 @@ dict_load_tablespace(
/* Try to open the tablespace. We set the 2nd param (fix_dict) to
false because we do not have an x-lock on dict_operation_lock */
- ulint fsp_flags = dict_tf_to_fsp_flags(table->flags, false);
+ ulint fsp_flags = dict_tf_to_fsp_flags(table->flags,
+ false,
+ dict_table_is_encrypted(table));
dberr_t err = fil_ibd_open(
true, false, FIL_TYPE_TABLESPACE, table->space,
fsp_flags, space_name, filepath, table);
@@ -3179,6 +3160,32 @@ err_exit:
}
}
+ /* We don't trust the table->flags2(retrieved from SYS_TABLES.MIX_LEN
+ field) if the datafiles are from 3.23.52 version. To identify this
+ version, we do the below check and reset the flags. */
+ if (!DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID)
+ && table->space == srv_sys_space.space_id()
+ && table->flags == 0) {
+ table->flags2 = 0;
+ }
+
+ DBUG_EXECUTE_IF("ib_table_invalid_flags",
+ if(strcmp(table->name.m_name, "test/t1") == 0) {
+ table->flags2 = 255;
+ table->flags = 255;
+ });
+
+ if (!dict_tf2_is_valid(table->flags, table->flags2)) {
+ ib::error() << "Table " << table->name << " in InnoDB"
+ " data dictionary contains invalid flags."
+ " SYS_TABLES.MIX_LEN=" << table->flags2;
+ table->flags2 &= ~(DICT_TF2_TEMPORARY|DICT_TF2_INTRINSIC);
+ dict_table_remove_from_cache(table);
+ table = NULL;
+ err = DB_FAIL;
+ goto func_exit;
+ }
+
/* Initialize table foreign_child value. Its value could be
changed when dict_load_foreigns() is called below */
table->fk_max_recusive_level = 0;
@@ -3203,6 +3210,7 @@ err_exit:
dict_table_remove_from_cache(table);
table = NULL;
} else {
+ dict_mem_table_fill_foreign_vcol_set(table);
table->fk_max_recusive_level = 0;
}
} else {
@@ -3353,99 +3361,6 @@ check_rec:
return(table);
}
-/***********************************************************************//**
-Loads a table id based on the index id.
-@return true if found */
-static
-bool
-dict_load_table_id_on_index_id(
-/*==================*/
- index_id_t index_id, /*!< in: index id */
- table_id_t* table_id) /*!< out: table id */
-{
- /* check hard coded indexes */
- switch(index_id) {
- case DICT_TABLES_ID:
- case DICT_COLUMNS_ID:
- case DICT_INDEXES_ID:
- case DICT_FIELDS_ID:
- *table_id = index_id;
- return true;
- case DICT_TABLE_IDS_ID:
- /* The following is a secondary index on SYS_TABLES */
- *table_id = DICT_TABLES_ID;
- return true;
- }
-
- bool found = false;
- mtr_t mtr;
-
- ut_ad(mutex_own(&(dict_sys->mutex)));
-
- /* NOTE that the operation of this function is protected by
- the dictionary mutex, and therefore no deadlocks can occur
- with other dictionary operations. */
-
- mtr_start(&mtr);
-
- btr_pcur_t pcur;
- const rec_t* rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
-
- while (rec) {
- ulint len;
- const byte* field = rec_get_nth_field_old(
- rec, DICT_FLD__SYS_INDEXES__ID, &len);
- ut_ad(len == 8);
-
- /* Check if the index id is the one searched for */
- if (index_id == mach_read_from_8(field)) {
- found = true;
- /* Now we get the table id */
- const byte* field = rec_get_nth_field_old(
- rec,
- DICT_FLD__SYS_INDEXES__TABLE_ID,
- &len);
- *table_id = mach_read_from_8(field);
- break;
- }
- mtr_commit(&mtr);
- mtr_start(&mtr);
- rec = dict_getnext_system(&pcur, &mtr);
- }
-
- btr_pcur_close(&pcur);
- mtr_commit(&mtr);
-
- return(found);
-}
-
-UNIV_INTERN
-dict_table_t*
-dict_table_open_on_index_id(
-/*==================*/
- index_id_t index_id, /*!< in: index id */
- bool dict_locked) /*!< in: dict locked */
-{
- if (!dict_locked) {
- mutex_enter(&dict_sys->mutex);
- }
-
- ut_ad(mutex_own(&dict_sys->mutex));
- table_id_t table_id;
- dict_table_t * table = NULL;
- if (dict_load_table_id_on_index_id(index_id, &table_id)) {
- bool local_dict_locked = true;
- table = dict_table_open_on_id(table_id,
- local_dict_locked,
- DICT_TABLE_OP_LOAD_TABLESPACE);
- }
-
- if (!dict_locked) {
- mutex_exit(&dict_sys->mutex);
- }
- return table;
-}
-
/********************************************************************//**
This function is called when the database is booted. Loads system table
index definitions except for the clustered index which is added to the
@@ -3953,3 +3868,96 @@ load_next_index:
DBUG_RETURN(DB_SUCCESS);
}
+
+/***********************************************************************//**
+Loads a table id based on the index id.
+@return true if found */
+static
+bool
+dict_load_table_id_on_index_id(
+/*===========================*/
+ index_id_t index_id, /*!< in: index id */
+ table_id_t* table_id) /*!< out: table id */
+{
+ /* check hard coded indexes */
+ switch(index_id) {
+ case DICT_TABLES_ID:
+ case DICT_COLUMNS_ID:
+ case DICT_INDEXES_ID:
+ case DICT_FIELDS_ID:
+ *table_id = index_id;
+ return true;
+ case DICT_TABLE_IDS_ID:
+ /* The following is a secondary index on SYS_TABLES */
+ *table_id = DICT_TABLES_ID;
+ return true;
+ }
+
+ bool found = false;
+ mtr_t mtr;
+
+ ut_ad(mutex_own(&(dict_sys->mutex)));
+
+ /* NOTE that the operation of this function is protected by
+ the dictionary mutex, and therefore no deadlocks can occur
+ with other dictionary operations. */
+
+ mtr_start(&mtr);
+
+ btr_pcur_t pcur;
+ const rec_t* rec = dict_startscan_system(&pcur, &mtr, SYS_INDEXES);
+
+ while (rec) {
+ ulint len;
+ const byte* field = rec_get_nth_field_old(
+ rec, DICT_FLD__SYS_INDEXES__ID, &len);
+ ut_ad(len == 8);
+
+ /* Check if the index id is the one searched for */
+ if (index_id == mach_read_from_8(field)) {
+ found = true;
+ /* Now we get the table id */
+ const byte* field = rec_get_nth_field_old(
+ rec,
+ DICT_FLD__SYS_INDEXES__TABLE_ID,
+ &len);
+ *table_id = mach_read_from_8(field);
+ break;
+ }
+ mtr_commit(&mtr);
+ mtr_start(&mtr);
+ rec = dict_getnext_system(&pcur, &mtr);
+ }
+
+ btr_pcur_close(&pcur);
+ mtr_commit(&mtr);
+
+ return(found);
+}
+
+UNIV_INTERN
+dict_table_t*
+dict_table_open_on_index_id(
+/*========================*/
+ index_id_t index_id, /*!< in: index id */
+ bool dict_locked) /*!< in: dict locked */
+{
+ if (!dict_locked) {
+ mutex_enter(&dict_sys->mutex);
+ }
+
+ ut_ad(mutex_own(&dict_sys->mutex));
+ table_id_t table_id;
+ dict_table_t * table = NULL;
+ if (dict_load_table_id_on_index_id(index_id, &table_id)) {
+ bool local_dict_locked = true;
+ table = dict_table_open_on_id(table_id,
+ local_dict_locked,
+ DICT_TABLE_OP_LOAD_TABLESPACE);
+ }
+
+ if (!dict_locked) {
+ mutex_exit(&dict_sys->mutex);
+ }
+ return table;
+}
diff --git a/storage/innobase/dict/dict0mem.cc b/storage/innobase/dict/dict0mem.cc
index 89e9861db45..b0d679d4619 100644
--- a/storage/innobase/dict/dict0mem.cc
+++ b/storage/innobase/dict/dict0mem.cc
@@ -190,36 +190,6 @@ dict_mem_table_create(
}
/****************************************************************//**
-Determines if a table belongs to a system database
-@return */
-UNIV_INTERN
-bool
-dict_mem_table_is_system(
-/*================*/
- char *name) /*!< in: table name */
-{
- ut_ad(name);
-
- /* table has the following format: database/table
- and some system table are of the form SYS_* */
- if (strchr(name, '/')) {
- int table_len = strlen(name);
- const char *system_db;
- int i = 0;
- while ((system_db = innobase_system_databases[i++])
- && (system_db != NullS)) {
- int len = strlen(system_db);
- if (table_len > len && !strncmp(name, system_db, len)) {
- return true;
- }
- }
- return false;
- } else {
- return true;
- }
-}
-
-/****************************************************************//**
Free a table memory object. */
void
dict_mem_table_free(
@@ -243,6 +213,7 @@ dict_mem_table_free(
dict_table_autoinc_destroy(table);
#endif /* UNIV_HOTBACKUP */
+ dict_mem_table_free_foreign_vcol_set(table);
dict_table_stats_latch_destroy(table);
table->foreign_set.~dict_foreign_set();
@@ -260,6 +231,10 @@ dict_mem_table_free(
UT_DELETE(vcol->v_indexes);
}
+ if (table->s_cols != NULL) {
+ UT_DELETE(table->s_cols);
+ }
+
mem_heap_free(table->heap);
}
@@ -433,6 +408,39 @@ dict_mem_table_add_v_col(
return(v_col);
}
+/** Adds a stored column definition to a table.
+@param[in] table table
+@param[in] num_base number of base columns. */
+void
+dict_mem_table_add_s_col(
+ dict_table_t* table,
+ ulint num_base)
+{
+ ulint i = table->n_def - 1;
+ dict_col_t* col = dict_table_get_nth_col(table, i);
+ dict_s_col_t s_col;
+
+ ut_ad(col != NULL);
+
+ if (table->s_cols == NULL) {
+ table->s_cols = UT_NEW_NOKEY(dict_s_col_list());
+ }
+
+ s_col.m_col = col;
+ s_col.s_pos = i + table->n_v_def;
+
+ if (num_base != 0) {
+ s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
+ table->heap, num_base * sizeof(dict_col_t*)));
+ } else {
+ s_col.base_col = NULL;
+ }
+
+ s_col.num_base = num_base;
+ table->s_cols->push_back(s_col);
+}
+
+
/**********************************************************************//**
Renames a column of a table in the data dictionary cache. */
static MY_ATTRIBUTE((nonnull))
@@ -452,7 +460,9 @@ dict_mem_table_col_rename_low(
size_t from_len = strlen(s), to_len = strlen(to);
- ut_ad(i < table->n_def);
+ ut_ad(i < table->n_def || is_virtual);
+ ut_ad(i < table->n_v_def || !is_virtual);
+
ut_ad(from_len <= NAME_LEN);
ut_ad(to_len <= NAME_LEN);
@@ -592,7 +602,7 @@ void
dict_mem_table_col_rename(
/*======================*/
dict_table_t* table, /*!< in/out: table */
- unsigned nth_col,/*!< in: column index */
+ ulint nth_col,/*!< in: column index */
const char* from, /*!< in: old column name */
const char* to, /*!< in: new column name */
bool is_virtual)
@@ -603,7 +613,7 @@ dict_mem_table_col_rename(
ut_ad((!is_virtual && nth_col < table->n_def)
|| (is_virtual && nth_col < table->n_v_def));
- for (unsigned i = 0; i < nth_col; i++) {
+ for (ulint i = 0; i < nth_col; i++) {
size_t len = strlen(s);
ut_ad(len > 0);
s += len + 1;
@@ -613,7 +623,8 @@ dict_mem_table_col_rename(
Proceed with the renaming anyway. */
ut_ad(!strcmp(from, s));
- dict_mem_table_col_rename_low(table, nth_col, to, s, is_virtual);
+ dict_mem_table_col_rename_low(table, static_cast<unsigned>(nth_col),
+ to, s, is_virtual);
}
/**********************************************************************//**
@@ -709,6 +720,8 @@ dict_mem_foreign_create(void)
foreign->heap = heap;
+ foreign->v_cols = NULL;
+
DBUG_PRINT("dict_mem_foreign_create", ("heap: %p", heap));
DBUG_RETURN(foreign);
@@ -773,6 +786,181 @@ dict_mem_referenced_table_name_lookup_set(
= foreign->referenced_table_name;
}
}
+
+/** Fill the virtual column set with virtual column information
+present in the given virtual index.
+@param[in] index virtual index
+@param[out] v_cols virtual column set. */
+static
+void
+dict_mem_fill_vcol_has_index(
+ const dict_index_t* index,
+ dict_vcol_set** v_cols)
+{
+ for (ulint i = 0; i < index->table->n_v_cols; i++) {
+ dict_v_col_t* v_col = dict_table_get_nth_v_col(
+ index->table, i);
+ if (!v_col->m_col.ord_part) {
+ continue;
+ }
+
+ dict_v_idx_list::iterator it;
+ for (it = v_col->v_indexes->begin();
+ it != v_col->v_indexes->end(); ++it) {
+ dict_v_idx_t v_idx = *it;
+
+ if (v_idx.index != index) {
+ continue;
+ }
+
+ if (*v_cols == NULL) {
+ *v_cols = UT_NEW_NOKEY(dict_vcol_set());
+ }
+
+ (*v_cols)->insert(v_col);
+ }
+ }
+}
+
+/** Fill the virtual column set with the virtual column of the index
+if the index contains given column name.
+@param[in] col_name column name
+@param[in] table innodb table object
+@param[out] v_cols set of virtual column information. */
+static
+void
+dict_mem_fill_vcol_from_v_indexes(
+ const char* col_name,
+ const dict_table_t* table,
+ dict_vcol_set** v_cols)
+{
+ /* virtual column can't be Primary Key, so start with
+ secondary index */
+ for (dict_index_t* index = dict_table_get_next_index(
+ dict_table_get_first_index(table));
+ index;
+ index = dict_table_get_next_index(index)) {
+
+ if (!dict_index_has_virtual(index)) {
+ continue;
+ }
+
+ for (ulint i = 0; i < index->n_fields; i++) {
+ dict_field_t* field =
+ dict_index_get_nth_field(index, i);
+
+ if (strcmp(field->name, col_name) == 0) {
+ dict_mem_fill_vcol_has_index(
+ index, v_cols);
+ }
+ }
+ }
+}
+
+/** Fill the virtual column set with virtual columns which have base columns
+as the given col_name
+@param[in] col_name column name
+@param[in] table table object
+@param[out] v_cols set of virtual columns. */
+static
+void
+dict_mem_fill_vcol_set_for_base_col(
+ const char* col_name,
+ const dict_table_t* table,
+ dict_vcol_set** v_cols)
+{
+ for (ulint i = 0; i < table->n_v_cols; i++) {
+ dict_v_col_t* v_col = dict_table_get_nth_v_col(table, i);
+
+ if (!v_col->m_col.ord_part) {
+ continue;
+ }
+
+ for (ulint j = 0; j < v_col->num_base; j++) {
+ if (strcmp(col_name, dict_table_get_col_name(
+ table,
+ v_col->base_col[j]->ind)) == 0) {
+
+ if (*v_cols == NULL) {
+ *v_cols = UT_NEW_NOKEY(dict_vcol_set());
+ }
+
+ (*v_cols)->insert(v_col);
+ }
+ }
+ }
+}
+
+/** Fills the dependent virtual columns in a set.
+Reason for being dependent are
+1) FK can be present on base column of virtual columns
+2) FK can be present on column which is a part of virtual index
+@param[in,out] foreign foreign key information. */
+void
+dict_mem_foreign_fill_vcol_set(
+ dict_foreign_t* foreign)
+{
+ ulint type = foreign->type;
+
+ if (type == 0) {
+ return;
+ }
+
+ for (ulint i = 0; i < foreign->n_fields; i++) {
+ /** FK can be present on base columns
+ of virtual columns. */
+ dict_mem_fill_vcol_set_for_base_col(
+ foreign->foreign_col_names[i],
+ foreign->foreign_table,
+ &foreign->v_cols);
+
+ /** FK can be present on the columns
+ which can be a part of virtual index. */
+ dict_mem_fill_vcol_from_v_indexes(
+ foreign->foreign_col_names[i],
+ foreign->foreign_table,
+ &foreign->v_cols);
+ }
+}
+
+/** Fill virtual columns set in each fk constraint present in the table.
+@param[in,out] table innodb table object. */
+void
+dict_mem_table_fill_foreign_vcol_set(
+ dict_table_t* table)
+{
+ dict_foreign_set fk_set = table->foreign_set;
+ dict_foreign_t* foreign;
+
+ dict_foreign_set::iterator it;
+ for (it = fk_set.begin(); it != fk_set.end(); ++it) {
+ foreign = *it;
+
+ dict_mem_foreign_fill_vcol_set(foreign);
+ }
+}
+
+/** Free the vcol_set from all foreign key constraint on the table.
+@param[in,out] table innodb table object. */
+void
+dict_mem_table_free_foreign_vcol_set(
+ dict_table_t* table)
+{
+ dict_foreign_set fk_set = table->foreign_set;
+ dict_foreign_t* foreign;
+
+ dict_foreign_set::iterator it;
+ for (it = fk_set.begin(); it != fk_set.end(); ++it) {
+
+ foreign = *it;
+
+ if (foreign->v_cols != NULL) {
+ UT_DELETE(foreign->v_cols);
+ foreign->v_cols = NULL;
+ }
+ }
+}
+
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
@@ -942,3 +1130,32 @@ operator<< (std::ostream& out, const dict_foreign_set& fk_set)
return(out);
}
+/****************************************************************//**
+Determines if a table belongs to a system database
+@return */
+bool
+dict_mem_table_is_system(
+/*================*/
+ char *name) /*!< in: table name */
+{
+ ut_ad(name);
+
+ /* table has the following format: database/table
+ and some system table are of the form SYS_* */
+ if (strchr(name, '/')) {
+ int table_len = strlen(name);
+ const char *system_db;
+ int i = 0;
+ while ((system_db = innobase_system_databases[i++])
+ && (system_db != NullS)) {
+ int len = strlen(system_db);
+ if (table_len > len && !strncmp(name, system_db, len)) {
+ return true;
+ }
+ }
+ return false;
+ } else {
+ return true;
+ }
+}
+
diff --git a/storage/innobase/dict/dict0stats.cc b/storage/innobase/dict/dict0stats.cc
index 67bf672ab49..3c25e37506b 100644
--- a/storage/innobase/dict/dict0stats.cc
+++ b/storage/innobase/dict/dict0stats.cc
@@ -930,14 +930,14 @@ dict_stats_update_transient(
if (dict_table_is_discarded(table)) {
/* Nothing to do. */
- dict_stats_empty_table(table, false);
+ dict_stats_empty_table(table, true);
return;
} else if (index == NULL) {
/* Table definition is corrupt */
ib::warn() << "Table " << table->name
<< " has no indexes. Cannot calculate statistics.";
- dict_stats_empty_table(table, false);
+ dict_stats_empty_table(table, true);
return;
}
@@ -2316,7 +2316,6 @@ storage.
allocate and free the trx object. If it is not NULL then it will be
rolled back only in the case of error, but not freed.
@return DB_SUCCESS or error code */
-static
dberr_t
dict_stats_save_index_stat(
dict_index_t* index,
@@ -3257,15 +3256,15 @@ dict_stats_update(
if (innodb_table_stats_not_found == false &&
table->stats_error_printed == false) {
- ib::error() << "Fetch of persistent statistics"
- " requested for table "
- << table->name
- << " but the required system tables "
- << TABLE_STATS_NAME_PRINT
- << " and " << INDEX_STATS_NAME_PRINT
- << " are not present or have unexpected"
- " structure. Using transient stats instead.";
- table->stats_error_printed = true;
+ ib::error() << "Fetch of persistent statistics"
+ " requested for table "
+ << table->name
+ << " but the required system tables "
+ << TABLE_STATS_NAME_PRINT
+ << " and " << INDEX_STATS_NAME_PRINT
+ << " are not present or have unexpected"
+ " structure. Using transient stats instead.";
+ table->stats_error_printed = true;
}
goto transient;
@@ -3337,12 +3336,12 @@ dict_stats_update(
if (innodb_table_stats_not_found == false &&
table->stats_error_printed == false) {
- ib::error() << "Error fetching persistent statistics"
- " for table "
- << table->name
- << " from " TABLE_STATS_NAME_PRINT " and "
- INDEX_STATS_NAME_PRINT ": " << ut_strerr(err)
- << ". Using transient stats method instead.";
+ ib::error() << "Error fetching persistent statistics"
+ " for table "
+ << table->name
+ << " from " TABLE_STATS_NAME_PRINT " and "
+ INDEX_STATS_NAME_PRINT ": " << ut_strerr(err)
+ << ". Using transient stats method instead.";
}
goto transient;
@@ -3842,120 +3841,6 @@ dict_stats_rename_table(
}
/*********************************************************************//**
-Save defragmentation result.
-@return DB_SUCCESS or error code */
-UNIV_INTERN
-dberr_t
-dict_stats_save_defrag_summary(
- dict_index_t* index) /*!< in: index */
-{
- dberr_t ret;
- lint now = (lint) ut_time();
-
- if (dict_stats_should_ignore_index(index)) {
- return DB_SUCCESS;
- }
-
- rw_lock_x_lock(dict_operation_lock);
- mutex_enter(&dict_sys->mutex);
- ret = dict_stats_save_index_stat(index, now, "n_pages_freed",
- index->stat_defrag_n_pages_freed,
- NULL,
- "Number of pages freed during"
- " last defragmentation run.",
- NULL);
-
- mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
- return (ret);
-}
-
-/*********************************************************************//**
-Save defragmentation stats for a given index.
-@return DB_SUCCESS or error code */
-UNIV_INTERN
-dberr_t
-dict_stats_save_defrag_stats(
- dict_index_t* index) /*!< in: index */
-{
- dberr_t ret;
-
- if (index->table->ibd_file_missing) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Cannot save defragment stats because "
- ".ibd file is missing.\n");
- return (DB_TABLESPACE_DELETED);
- }
- if (dict_index_is_corrupted(index)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: Cannot save defragment stats because "
- "index is corrupted.\n");
- return(DB_CORRUPTION);
- }
-
- if (dict_stats_should_ignore_index(index)) {
- return DB_SUCCESS;
- }
-
- lint now = (lint) ut_time();
- mtr_t mtr;
- ulint n_leaf_pages=0;
- ulint n_leaf_reserved=0;
- mtr_start(&mtr);
- mtr_s_lock(dict_index_get_lock(index), &mtr);
-
- n_leaf_reserved = btr_get_size_and_reserved(index, BTR_N_LEAF_PAGES,
- &n_leaf_pages, &mtr);
- mtr_commit(&mtr);
-
- if (n_leaf_reserved == ULINT_UNDEFINED) {
- // The index name is different during fast index creation,
- // so the stats won't be associated with the right index
- // for later use. We just return without saving.
- return DB_SUCCESS;
- }
-
- rw_lock_x_lock(dict_operation_lock);
-
- mutex_enter(&dict_sys->mutex);
- ret = dict_stats_save_index_stat(index, now, "n_page_split",
- index->stat_defrag_n_page_split,
- NULL,
- "Number of new page splits on leaves"
- " since last defragmentation.",
- NULL);
- if (ret != DB_SUCCESS) {
- goto end;
- }
-
- ret = dict_stats_save_index_stat(
- index, now, "n_leaf_pages_defrag",
- n_leaf_pages,
- NULL,
- "Number of leaf pages when this stat is saved to disk",
- NULL);
- if (ret != DB_SUCCESS) {
- goto end;
- }
-
- ret = dict_stats_save_index_stat(
- index, now, "n_leaf_pages_reserved",
- n_leaf_reserved,
- NULL,
- "Number of pages reserved for this index leaves when this stat "
- "is saved to disk",
- NULL);
-
-end:
- mutex_exit(&dict_sys->mutex);
- rw_lock_x_unlock(dict_operation_lock);
-
- return (ret);
-}
-
-/*********************************************************************//**
Renames an index in InnoDB persistent stats storage.
This function creates its own transaction and commits it.
@return DB_SUCCESS or error code. DB_STATS_DO_NOT_EXIST will be returned
diff --git a/storage/innobase/dict/dict0stats_bg.cc b/storage/innobase/dict/dict0stats_bg.cc
index eca3756152a..dbc8e90bed6 100644
--- a/storage/innobase/dict/dict0stats_bg.cc
+++ b/storage/innobase/dict/dict0stats_bg.cc
@@ -24,9 +24,9 @@ Created Apr 25, 2012 Vasil Dimov
*******************************************************/
#include "dict0dict.h"
-#include "dict0dict.h"
#include "dict0stats.h"
#include "dict0stats_bg.h"
+#include "dict0defrag_bg.h"
#include "row0mysql.h"
#include "srv0start.h"
#include "ut0new.h"
@@ -45,15 +45,27 @@ Created Apr 25, 2012 Vasil Dimov
/** Event to wake up the stats thread */
os_event_t dict_stats_event = NULL;
+/** Variable to initiate shutdown the dict stats thread. Note we don't
+use 'srv_shutdown_state' because we want to shutdown dict stats thread
+before purge thread. */
+bool dict_stats_start_shutdown = false;
+
+/** Event to wait for shutdown of the dict stats thread */
+os_event_t dict_stats_shutdown_event = NULL;
+
+#ifdef UNIV_DEBUG
+/** Used by SET GLOBAL innodb_dict_stats_disabled_debug = 1; */
+my_bool innodb_dict_stats_disabled_debug;
+
+static os_event_t dict_stats_disabled_event;
+#endif /* UNIV_DEBUG */
+
/** This mutex protects the "recalc_pool" variable. */
static ib_mutex_t recalc_pool_mutex;
-static ib_mutex_t defrag_pool_mutex;
-static mysql_pfs_key_t defrag_pool_mutex_key;
/** The number of tables that can be added to "recalc_pool" before
it is enlarged */
static const ulint RECALC_POOL_INITIAL_SLOTS = 128;
-static const ulint DEFRAG_POOL_INITIAL_SLOTS = 128;
/** Allocator type, used by std::vector */
typedef ut_allocator<table_id_t>
@@ -73,39 +85,23 @@ typedef recalc_pool_t::iterator
by background statistics gathering. */
static recalc_pool_t* recalc_pool;
-/** Indices whose defrag stats need to be saved to persistent storage.*/
-struct defrag_pool_item_t {
- table_id_t table_id;
- index_id_t index_id;
-};
-
-typedef ut_allocator<defrag_pool_item_t>
- defrag_pool_allocator_t;
-typedef std::vector<defrag_pool_item_t, defrag_pool_allocator_t>
- defrag_pool_t;
-static defrag_pool_t* defrag_pool;
-typedef defrag_pool_t::iterator defrag_pool_iterator_t;
/*****************************************************************//**
Initialize the recalc pool, called once during thread initialization. */
static
void
-dict_stats_pool_init()
+dict_stats_recalc_pool_init()
/*=========================*/
{
ut_ad(!srv_read_only_mode);
/* JAN: TODO: MySQL 5.7 PSI
const PSI_memory_key key = mem_key_dict_stats_bg_recalc_pool_t;
- const PSI_memory_key key2 = mem_key_dict_defrag_pool_t;
recalc_pool = UT_NEW(recalc_pool_t(recalc_pool_allocator_t(key)), key);
- defrag_pool = UT_NEW(defrag_pool_t(defrag_pool_allocator_t(key2)), key2);
- defrag_pool->reserve(DEFRAG_POOL_INITIAL_SLOTS);
recalc_pool->reserve(RECALC_POOL_INITIAL_SLOTS);
*/
recalc_pool = new std::vector<table_id_t, recalc_pool_allocator_t>();
- defrag_pool = new std::vector<defrag_pool_item_t, defrag_pool_allocator_t>();
}
/*****************************************************************//**
@@ -113,16 +109,14 @@ Free the resources occupied by the recalc pool, called once during
thread de-initialization. */
static
void
-dict_stats_pool_deinit()
-/*====================*/
+dict_stats_recalc_pool_deinit()
+/*===========================*/
{
ut_ad(!srv_read_only_mode);
recalc_pool->clear();
- defrag_pool->clear();
UT_DELETE(recalc_pool);
- UT_DELETE(defrag_pool);
}
/*****************************************************************//**
@@ -217,111 +211,6 @@ dict_stats_recalc_pool_del(
}
/*****************************************************************//**
-Add an index in a table to the defrag pool, which is processed by the
-background stats gathering thread. Only the table id and index id are
-added to the list, so the table can be closed after being enqueued and
-it will be opened when needed. If the table or index does not exist later
-(has been DROPped), then it will be removed from the pool and skipped. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_add(
-/*=======================*/
- const dict_index_t* index) /*!< in: table to add */
-{
- defrag_pool_item_t item;
-
- ut_ad(!srv_read_only_mode);
-
- mutex_enter(&defrag_pool_mutex);
-
- /* quit if already in the list */
- for (defrag_pool_iterator_t iter = defrag_pool->begin();
- iter != defrag_pool->end();
- ++iter) {
- if ((*iter).table_id == index->table->id
- && (*iter).index_id == index->id) {
- mutex_exit(&defrag_pool_mutex);
- return;
- }
- }
-
- item.table_id = index->table->id;
- item.index_id = index->id;
- defrag_pool->push_back(item);
-
- mutex_exit(&defrag_pool_mutex);
-
- os_event_set(dict_stats_event);
-}
-
-/*****************************************************************//**
-Get an index from the auto defrag pool. The returned index id is removed
-from the pool.
-@return true if the pool was non-empty and "id" was set, false otherwise */
-static
-bool
-dict_stats_defrag_pool_get(
-/*=======================*/
- table_id_t* table_id, /*!< out: table id, or unmodified if
- list is empty */
- index_id_t* index_id) /*!< out: index id, or unmodified if
- list is empty */
-{
- ut_ad(!srv_read_only_mode);
-
- mutex_enter(&defrag_pool_mutex);
-
- if (defrag_pool->empty()) {
- mutex_exit(&defrag_pool_mutex);
- return(false);
- }
-
- defrag_pool_item_t& item = defrag_pool->back();
- *table_id = item.table_id;
- *index_id = item.index_id;
-
- defrag_pool->pop_back();
-
- mutex_exit(&defrag_pool_mutex);
-
- return(true);
-}
-
-/*****************************************************************//**
-Delete a given index from the auto defrag pool. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_del(
-/*=======================*/
- const dict_table_t* table, /*!<in: if given, remove
- all entries for the table */
- const dict_index_t* index) /*!< in: if given, remove this index */
-{
- ut_a((table && !index) || (!table && index));
- ut_ad(!srv_read_only_mode);
- ut_ad(mutex_own(&dict_sys->mutex));
-
- mutex_enter(&defrag_pool_mutex);
-
- defrag_pool_iterator_t iter = defrag_pool->begin();
- while (iter != defrag_pool->end()) {
- if ((table && (*iter).table_id == table->id)
- || (index
- && (*iter).table_id == index->table->id
- && (*iter).index_id == index->id)) {
- /* erase() invalidates the iterator */
- iter = defrag_pool->erase(iter);
- if (index)
- break;
- } else {
- iter++;
- }
- }
-
- mutex_exit(&defrag_pool_mutex);
-}
-
-/*****************************************************************//**
Wait until background stats thread has stopped using the specified table.
The caller must have locked the data dictionary using
row_mysql_lock_data_dictionary() and this function may unlock it temporarily
@@ -352,6 +241,9 @@ dict_stats_thread_init()
ut_a(!srv_read_only_mode);
dict_stats_event = os_event_create(0);
+ dict_stats_shutdown_event = os_event_create(0);
+
+ ut_d(dict_stats_disabled_event = os_event_create(0));
/* The recalc_pool_mutex is acquired from:
1) the background stats gathering thread before any other latch
@@ -369,10 +261,9 @@ dict_stats_thread_init()
mutex_create(LATCH_ID_RECALC_POOL, &recalc_pool_mutex);
- /* We choose SYNC_STATS_DEFRAG to be below SYNC_FSP_PAGE. */
- mutex_create(LATCH_ID_DEFRAGMENT_MUTEX, &defrag_pool_mutex);
+ dict_stats_recalc_pool_init();
+ dict_defrag_pool_init();
- dict_stats_pool_init();
}
/*****************************************************************//**
@@ -385,13 +276,21 @@ dict_stats_thread_deinit()
ut_a(!srv_read_only_mode);
ut_ad(!srv_dict_stats_thread_active);
- dict_stats_pool_deinit();
+ dict_stats_recalc_pool_deinit();
+ dict_defrag_pool_deinit();
mutex_free(&recalc_pool_mutex);
- mutex_free(&defrag_pool_mutex);
+
+#ifdef UNIV_DEBUG
+ os_event_destroy(dict_stats_disabled_event);
+ dict_stats_disabled_event = NULL;
+#endif /* UNIV_DEBUG */
os_event_destroy(dict_stats_event);
+ os_event_destroy(dict_stats_shutdown_event);
dict_stats_event = NULL;
+ dict_stats_shutdown_event = NULL;
+ dict_stats_start_shutdown = false;
}
/*****************************************************************//**
@@ -459,69 +358,43 @@ dict_stats_process_entry_from_recalc_pool()
mutex_enter(&dict_sys->mutex);
- table->stats_bg_flag &= ~BG_STAT_IN_PROGRESS;
+ table->stats_bg_flag = BG_STAT_NONE;
dict_table_close(table, TRUE, FALSE);
mutex_exit(&dict_sys->mutex);
}
-/*****************************************************************//**
-Get the first index that has been added for updating persistent defrag
-stats and eventually save its stats. */
-static
+#ifdef UNIV_DEBUG
+/** Disables dict stats thread. It's used by:
+ SET GLOBAL innodb_dict_stats_disabled_debug = 1 (0).
+@param[in] thd thread handle
+@param[in] var pointer to system variable
+@param[out] var_ptr where the formal string goes
+@param[in] save immediate result from check function */
void
-dict_stats_process_entry_from_defrag_pool()
-/*=======================================*/
+dict_stats_disabled_debug_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save)
{
- table_id_t table_id;
- index_id_t index_id;
-
- ut_ad(!srv_read_only_mode);
-
- /* pop the first index from the auto defrag pool */
- if (!dict_stats_defrag_pool_get(&table_id, &index_id)) {
- /* no index in defrag pool */
- return;
- }
-
- dict_table_t* table;
-
- mutex_enter(&dict_sys->mutex);
-
- /* If the table is no longer cached, we've already lost the in
- memory stats so there's nothing really to write to disk. */
- table = dict_table_open_on_id(table_id, TRUE,
- DICT_TABLE_OP_OPEN_ONLY_IF_CACHED);
-
- if (table == NULL) {
- mutex_exit(&dict_sys->mutex);
- return;
- }
+ /* This method is protected by mutex, as every SET GLOBAL .. */
+ ut_ad(dict_stats_disabled_event != NULL);
- /* Check whether table is corrupted */
- if (table->corrupted) {
- dict_table_close(table, TRUE, FALSE);
- mutex_exit(&dict_sys->mutex);
- return;
- }
- mutex_exit(&dict_sys->mutex);
+ const bool disable = *static_cast<const my_bool*>(save);
- dict_index_t* index = dict_table_find_index_on_id(table, index_id);
+ const int64_t sig_count = os_event_reset(dict_stats_disabled_event);
- if (index == NULL) {
- return;
- }
+ innodb_dict_stats_disabled_debug = disable;
- /* Check whether index is corrupted */
- if (dict_index_is_corrupted(index)) {
- dict_table_close(table, FALSE, FALSE);
- return;
+ if (disable) {
+ os_event_set(dict_stats_event);
+ os_event_wait_low(dict_stats_disabled_event, sig_count);
}
-
- dict_stats_save_defrag_stats(index);
- dict_table_close(table, FALSE, FALSE);
}
+#endif /* UNIV_DEBUG */
+
/*****************************************************************//**
This is the thread for background stats gathering. It pops tables, from
@@ -545,7 +418,7 @@ DECLARE_THREAD(dict_stats_thread)(
srv_dict_stats_thread_active = TRUE;
- while (!SHUTTING_DOWN()) {
+ while (!dict_stats_start_shutdown) {
/* Wake up periodically even if not signaled. This is
because we may lose an event - if the below call to
@@ -555,23 +428,44 @@ DECLARE_THREAD(dict_stats_thread)(
os_event_wait_time(
dict_stats_event, MIN_RECALC_INTERVAL * 1000000);
- if (SHUTTING_DOWN()) {
+#ifdef UNIV_DEBUG
+ while (innodb_dict_stats_disabled_debug) {
+ os_event_set(dict_stats_disabled_event);
+ if (dict_stats_start_shutdown) {
+ break;
+ }
+ os_event_wait_time(
+ dict_stats_event, 100000);
+ }
+#endif /* UNIV_DEBUG */
+
+ if (dict_stats_start_shutdown) {
break;
}
dict_stats_process_entry_from_recalc_pool();
-
- while (defrag_pool->size())
- dict_stats_process_entry_from_defrag_pool();
+ dict_defrag_process_entries_from_defrag_pool();
os_event_reset(dict_stats_event);
}
srv_dict_stats_thread_active = FALSE;
+ os_event_set(dict_stats_shutdown_event);
+ my_thread_end();
+
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit instead of return(). */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
+
+/** Shutdown the dict stats thread. */
+void
+dict_stats_shutdown()
+{
+ dict_stats_start_shutdown = true;
+ os_event_set(dict_stats_event);
+ os_event_wait(dict_stats_shutdown_event);
+}
diff --git a/storage/innobase/fil/fil0crypt.cc b/storage/innobase/fil/fil0crypt.cc
index fb872628e4f..9062bf1586b 100644
--- a/storage/innobase/fil/fil0crypt.cc
+++ b/storage/innobase/fil/fil0crypt.cc
@@ -2353,7 +2353,7 @@ DECLARE_THREAD(fil_crypt_thread)(
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index a28be694f94..3d34de6c51e 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -29,12 +29,13 @@ Created 10/25/1995 Heikki Tuuri
#include "fsp0pagecompress.h"
#include "fil0crypt.h"
+#ifndef UNIV_HOTBACKUP
#include "btr0btr.h"
#include "buf0buf.h"
-#include "buf0flu.h"
#include "dict0boot.h"
#include "dict0dict.h"
#include "fsp0file.h"
+#include "fsp0file.h"
#include "fsp0fsp.h"
#include "fsp0space.h"
#include "fsp0sysspace.h"
@@ -50,14 +51,28 @@ Created 10/25/1995 Heikki Tuuri
#include "srv0start.h"
#include "trx0purge.h"
#include "ut0new.h"
-#ifndef UNIV_HOTBACKUP
# include "buf0lru.h"
# include "ibuf0ibuf.h"
# include "os0event.h"
# include "sync0sync.h"
-#else /* !UNIV_HOTBACKUP */
-# include "srv0srv.h"
#endif /* !UNIV_HOTBACKUP */
+#include "buf0flu.h"
+#include "srv0start.h"
+#include "trx0purge.h"
+#include "ut0new.h"
+
+/** Tries to close a file in the LRU list. The caller must hold the fil_sys
+mutex.
+@return true if success, false if should retry later; since i/o's
+generally complete in < 100 ms, and as InnoDB writes at most 128 pages
+from the buffer pool in a batch, and then immediately flushes the
+files, there is a good chance that the next time we find a suitable
+node from the LRU list.
+@param[in] print_info if true, prints information why it
+ cannot close a file */
+static
+bool
+fil_try_to_close_file_in_LRU(bool print_info);
/*
IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
@@ -123,10 +138,10 @@ const char general_space_name[] = "innodb_general";
current working directory ".", but in the MySQL Embedded Server Library
it is an absolute path. */
const char* fil_path_to_mysql_datadir;
-Folder folder_mysql_datadir;
+Folder folder_mysql_datadir;
/** Common InnoDB file extentions */
-const char* dot_ext[] = { "", ".ibd", ".isl", ".cfg" };
+const char* dot_ext[] = { "", ".ibd", ".isl", ".cfg", ".cfp" };
/** The number of fsyncs done to the log */
ulint fil_n_log_flushes = 0;
@@ -144,7 +159,7 @@ fil_addr_t fil_addr_null = {FIL_NULL, 0};
/** The tablespace memory cache. This variable is NULL before the module is
initialized. */
-static fil_system_t* fil_system = NULL;
+fil_system_t* fil_system = NULL;
#ifdef UNIV_HOTBACKUP
static ulint srv_data_read;
@@ -349,7 +364,6 @@ fil_space_get_by_name(
return(space);
}
-#ifndef UNIV_HOTBACKUP
/** Look up a tablespace.
The caller should hold an InnoDB table lock or a MDL that prevents
the tablespace from being dropped during the operation,
@@ -369,33 +383,8 @@ fil_space_get(
ut_ad(space == NULL || space->purpose != FIL_TYPE_LOG);
return(space);
}
-/*******************************************************************//**
-Returns the version number of a tablespace, -1 if not found.
-@return version number, -1 if the tablespace does not exist in the
-memory cache */
-UNIV_INTERN
-ib_uint64_t
-fil_space_get_version(
-/*==================*/
- ulint id) /*!< in: space id */
-{
- fil_space_t* space;
- ib_uint64_t version = -1;
-
- ut_ad(fil_system);
-
- mutex_enter(&fil_system->mutex);
-
- space = fil_space_get_by_id(id);
-
- if (space) {
- version = space->tablespace_version;
- }
- mutex_exit(&fil_system->mutex);
-
- return(version);
-}
+#ifndef UNIV_HOTBACKUP
/** Returns the latch of a file space.
@param[in] id space id
@param[out] flags tablespace flags
@@ -592,7 +581,19 @@ fil_node_create_low(
node->block_size = stat_info.block_size;
- if (!(IORequest::is_punch_hole_supported() && punch_hole)
+ /* In this debugging mode, we can overcome the limitation of some
+ OSes like Windows that support Punch Hole but have a hole size
+ effectively too large. By setting the block size to be half the
+ page size, we can bypass one of the checks that would normally
+ turn Page Compression off. This execution mode allows compression
+ to be tested even when full punch hole support is not available. */
+ DBUG_EXECUTE_IF("ignore_punch_hole",
+ node->block_size = ut_min(stat_info.block_size,
+ static_cast<size_t>(UNIV_PAGE_SIZE / 2));
+ );
+
+ if (!IORequest::is_punch_hole_supported()
+ || !punch_hole
|| node->block_size >= srv_page_size) {
fil_no_punch_hole(node);
@@ -650,9 +651,9 @@ fil_node_open_file(
bool success;
byte* buf2;
byte* page;
- ulint space_id;
ulint flags;
ulint min_size;
+ ulint space_id;
bool read_only_mode;
fil_space_t* space = node->space;
@@ -675,18 +676,22 @@ fil_node_open_file(
file read function os_file_read() in Windows to read
from a file opened for async I/O! */
+retry:
node->handle = os_file_create_simple_no_error_handling(
innodb_data_file_key, node->name, OS_FILE_OPEN,
OS_FILE_READ_ONLY, read_only_mode, &success);
if (!success) {
/* The following call prints an error message */
- os_file_get_last_error(true);
+ ulint err = os_file_get_last_error(true);
+ if (err == EMFILE + 100) {
+ if (fil_try_to_close_file_in_LRU(true))
+ goto retry;
+ }
ib::warn() << "Cannot open '" << node->name << "'."
" Have you deleted .ibd files under a"
" running mysqld server?";
-
return(false);
}
@@ -730,30 +735,13 @@ fil_node_open_file(
if (size_bytes < min_size) {
- ib::error() << "The size of tablespace file "
+ ib::error() << "The size of tablespace " << space_id << " file "
<< node->name << " is only " << size_bytes
<< ", should be at least " << min_size << "!";
ut_error;
}
- if (space_id != space->id) {
- ib::fatal() << "Tablespace id is " << space->id
- << " in the data dictionary but in file "
- << node->name << " it is " << space_id << "!";
- }
-
- const page_size_t space_page_size(space->flags);
-
- if (!page_size.equals_to(space_page_size)) {
- ib::fatal() << "Tablespace file " << node->name
- << " has page size " << page_size
- << " (flags=" << ib::hex(flags) << ") but the"
- " data dictionary expects page size "
- << space_page_size << " (flags="
- << ib::hex(space->flags) << ")!";
- }
-
if (space->flags != flags) {
ulint sflags = (space->flags & ~FSP_FLAGS_MASK_DATA_DIR);
ulint fflags = (flags & ~FSP_FLAGS_MASK_DATA_DIR_ORACLE);
@@ -763,11 +751,13 @@ fil_node_open_file(
it. */
if (sflags == fflags) {
- fprintf(stderr,
- "InnoDB: Warning: Table flags 0x%lx"
- " in the data dictionary but in file %s are 0x%lx!\n"
- " Temporally corrected because DATA_DIR option to 0x%lx.\n",
- space->flags, node->name, flags, space->flags);
+ ib::warn()
+ << "Tablespace " << space_id
+ << " flags " << space->flags
+ << " in the data dictionary but in file " << node->name
+ << " are " << flags
+ << ". Temporally corrected because DATA_DIR option to "
+ << space->flags;
flags = space->flags;
} else {
@@ -788,8 +778,7 @@ fil_node_open_file(
page, FSP_FREE_LIMIT);
ulint free_len = flst_get_len(
FSP_HEADER_OFFSET + FSP_FREE + page);
- ut_ad(space->size_in_header == 0
- || space->size_in_header == size);
+
ut_ad(space->free_limit == 0
|| space->free_limit == free_limit);
ut_ad(space->free_len == 0
@@ -801,16 +790,35 @@ fil_node_open_file(
ut_free(buf2);
+#ifdef MYSQL_ENCRYPTION
+ /* For encrypted tablespace, we need to check the
+ encrytion key and iv(initial vector) is readed. */
+ if (FSP_FLAGS_GET_ENCRYPTION(flags)
+ && !recv_recovery_is_on()) {
+ if (space->encryption_type != Encryption::AES) {
+ ib::error()
+ << "Can't read encryption"
+ << " key from file "
+ << node->name << "!";
+ return(false);
+ }
+ }
+#endif
+
if (node->size == 0) {
ulint extent_size;
extent_size = page_size.physical() * FSP_EXTENT_SIZE;
+
+ /* After apply-incremental, tablespaces are not extended
+ to a whole megabyte. Do not cut off valid data. */
+#ifndef UNIV_HOTBACKUP
/* Truncate the size to a multiple of extent size. */
if (size_bytes >= extent_size) {
size_bytes = ut_2pow_round(size_bytes,
extent_size);
}
-
+#endif /* !UNIV_HOTBACKUP */
node->size = (ulint)
(size_bytes / page_size.physical());
@@ -896,20 +904,20 @@ fil_node_close_file(
}
}
-/********************************************************************//**
-Tries to close a file in the LRU list. The caller must hold the fil_sys
+/** Tries to close a file in the LRU list. The caller must hold the fil_sys
mutex.
@return true if success, false if should retry later; since i/o's
generally complete in < 100 ms, and as InnoDB writes at most 128 pages
from the buffer pool in a batch, and then immediately flushes the
files, there is a good chance that the next time we find a suitable
-node from the LRU list */
+node from the LRU list.
+@param[in] print_info if true, prints information why it
+ cannot close a file*/
static
bool
fil_try_to_close_file_in_LRU(
-/*=========================*/
- bool print_info) /*!< in: if true, prints information why it
- cannot close a file */
+
+ bool print_info)
{
fil_node_t* node;
@@ -1078,7 +1086,7 @@ fil_mutex_enter_and_prepare_for_io(
os_aio_simulated_wake_handler_threads();
os_thread_sleep(20000);
-#endif
+#endif /* !UNIV_HOTBACKUP */
/* Flush tablespaces so that we can close modified files in
the LRU list. */
@@ -1303,6 +1311,8 @@ fil_space_create(
UT_LIST_INIT(space->chain, &fil_node_t::chain);
+ /* This warning is not applicable while MEB scanning the redo logs */
+#ifndef UNIV_HOTBACKUP
if (fil_type_is_data(purpose)
&& !recv_recovery_on
&& id > fil_system->max_assigned_id) {
@@ -1317,16 +1327,20 @@ fil_space_create(
fil_system->max_assigned_id = id;
}
-
+#endif /* !UNIV_HOTBACKUP */
space->purpose = purpose;
space->flags = flags;
space->magic_n = FIL_SPACE_MAGIC_N;
+ space->encryption_type = Encryption::NONE;
+
rw_lock_create(fil_space_latch_key, &space->latch, SYNC_FSP);
if (space->purpose == FIL_TYPE_TEMPORARY) {
+#ifndef UNIV_HOTBACKUP
ut_d(space->latch.set_temp_fsp());
+#endif /* !UNIV_HOTBACKUP */
}
HASH_INSERT(fil_space_t, hash, fil_system->spaces, id, space);
@@ -1885,15 +1899,12 @@ fil_write_flushed_lsn(
if (err == DB_SUCCESS) {
mach_write_to_8(buf + FIL_PAGE_FILE_FLUSH_LSN_OR_KEY_VERSION, lsn);
-
err = fil_write(page_id, univ_page_size, 0,
univ_page_size.physical(), buf);
-
fil_flush_file_spaces(FIL_TYPE_TABLESPACE);
}
ut_free(buf1);
-
return(err);
}
@@ -1992,7 +2003,7 @@ fil_create_directory_for_tablename(
memcpy(path + len + 1, name, namend - name);
path[len + (namend - name) + 1] = 0;
- os_normalize_path_for_win(path);
+ os_normalize_path(path);
bool success = os_file_create_directory(path, false);
ut_a(success);
@@ -2000,7 +2011,6 @@ fil_create_directory_for_tablename(
ut_free(path);
}
-#ifndef UNIV_HOTBACKUP
/** Write a log record about an operation on a tablespace file.
@param[in] type MLOG_FILE_NAME or MLOG_FILE_DELETE
or MLOG_FILE_CREATE2 or MLOG_FILE_RENAME2
@@ -2080,7 +2090,7 @@ fil_op_write_log(
ut_ad(0);
}
}
-
+#ifndef UNIV_HOTBACKUP
/** Write redo log for renaming a file.
@param[in] space_id tablespace id
@param[in] first_page_no first page number in the file
@@ -2102,7 +2112,7 @@ fil_name_write_rename(
MLOG_FILE_RENAME2,
space_id, first_page_no, old_name, new_name, 0, mtr);
}
-
+#endif /* !UNIV_HOTBACKUP */
/** Write MLOG_FILE_NAME for a file.
@param[in] space_id tablespace id
@param[in] first_page_no first page number in the file
@@ -2119,7 +2129,6 @@ fil_name_write(
fil_op_write_log(
MLOG_FILE_NAME, space_id, first_page_no, name, NULL, 0, mtr);
}
-
/** Write MLOG_FILE_NAME for a file.
@param[in] space tablespace
@param[in] first_page_no first page number in the file
@@ -2135,8 +2144,8 @@ fil_name_write(
{
fil_name_write(space->id, first_page_no, file->name, mtr);
}
-#endif
+#ifndef UNIV_HOTBACKUP
/********************************************************//**
Recreates table indexes by applying
TRUNCATE log record during recovery.
@@ -2377,7 +2386,7 @@ fil_recreate_tablespace(
return(err);
}
-
+#endif /* UNIV_HOTBACKUP */
/** Replay a file rename operation if possible.
@param[in] space_id tablespace identifier
@param[in] first_page_no first page number in the file
@@ -2440,15 +2449,10 @@ fil_op_replay_rename(
ut_free(dir);
/* New path must not exist. */
- bool exists;
- os_file_type_t ftype;
-
- if (!os_file_status(new_name, &exists, &ftype)
- || exists) {
- ib::error() << "Cannot replay rename '" << name
- << "' to '" << new_name << "'"
- " for space ID " << space_id
- << " because the target file exists."
+ dberr_t err = fil_rename_tablespace_check(
+ space_id, name, new_name, false);
+ if (err != DB_SUCCESS) {
+ ib::error() << " Cannot replay file rename."
" Remove either file and try again.";
return(false);
}
@@ -2839,6 +2843,7 @@ fil_delete_tablespace(
return(err);
}
+#ifndef UNIV_HOTBACKUP
/** Truncate the tablespace to needed size.
@param[in] space_id id of tablespace to truncate
@param[in] size_in_pages truncate size.
@@ -3027,9 +3032,8 @@ fil_space_is_redo_skipped(
return(is_redo_skipped);
}
-#endif
+#endif /* UNIV_DEBUG */
-#ifndef UNIV_HOTBACKUP
/*******************************************************************//**
Discards a single-table tablespace. The tablespace must be cached in the
memory cache. Discarding is like deleting a tablespace, but
@@ -3076,51 +3080,6 @@ fil_discard_tablespace(
#endif /* !UNIV_HOTBACKUP */
/*******************************************************************//**
-Renames the memory cache structures of a single-table tablespace.
-@return true if success */
-static
-bool
-fil_rename_tablespace_in_mem(
-/*=========================*/
- fil_space_t* space, /*!< in: tablespace memory object */
- fil_node_t* node, /*!< in: file node of that tablespace */
- const char* new_name, /*!< in: new name */
- const char* new_path) /*!< in: new file path */
-{
- fil_space_t* space2;
- const char* old_name = space->name;
-
- ut_ad(mutex_own(&fil_system->mutex));
-
- space2 = fil_space_get_by_name(old_name);
- if (space != space2) {
- ib::error() << "Cannot find " << old_name
- << " in tablespace memory cache";
- return(false);
- }
-
- space2 = fil_space_get_by_name(new_name);
- if (space2 != NULL) {
- ib::error() << new_name
- << " is already in tablespace memory cache";
-
- return(false);
- }
-
- HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
- ut_fold_string(space->name), space);
- ut_free(space->name);
- ut_free(node->name);
-
- space->name = mem_strdup(new_name);
- node->name = mem_strdup(new_path);
-
- HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
- ut_fold_string(space->name), space);
- return(true);
-}
-
-/*******************************************************************//**
Allocates and builds a file name from a path, a table or tablespace name
and a suffix. The string must be freed by caller with ut_free().
@param[in] path NULL or the direcory path or the full path and filename.
@@ -3224,6 +3183,47 @@ fil_make_filepath(
return(full_name);
}
+/** Test if a tablespace file can be renamed to a new filepath by checking
+if that the old filepath exists and the new filepath does not exist.
+@param[in] space_id tablespace id
+@param[in] old_path old filepath
+@param[in] new_path new filepath
+@param[in] is_discarded whether the tablespace is discarded
+@return innodb error code */
+dberr_t
+fil_rename_tablespace_check(
+ ulint space_id,
+ const char* old_path,
+ const char* new_path,
+ bool is_discarded)
+{
+ bool exists = false;
+ os_file_type_t ftype;
+
+ if (!is_discarded
+ && os_file_status(old_path, &exists, &ftype)
+ && !exists) {
+ ib::error() << "Cannot rename '" << old_path
+ << "' to '" << new_path
+ << "' for space ID " << space_id
+ << " because the source file"
+ << " does not exist.";
+ return(DB_TABLESPACE_NOT_FOUND);
+ }
+
+ exists = false;
+ if (!os_file_status(new_path, &exists, &ftype) || exists) {
+ ib::error() << "Cannot rename '" << old_path
+ << "' to '" << new_path
+ << "' for space ID " << space_id
+ << " because the target file exists."
+ " Remove the target file and try again.";
+ return(DB_TABLESPACE_EXISTS);
+ }
+
+ return(DB_SUCCESS);
+}
+
/** Rename a single-table tablespace.
The tablespace must exist in the memory cache.
@param[in] id tablespace identifier
@@ -3245,22 +3245,16 @@ fil_rename_tablespace(
fil_space_t* space;
fil_node_t* node;
ulint count = 0;
- char* old_name = NULL;
- const char* new_path = new_path_in;
ut_a(id != 0);
- if (new_path == NULL) {
- new_path = fil_make_filepath(NULL, new_name, IBD, false);
- }
-
ut_ad(strchr(new_name, '/') != NULL);
- ut_ad(strchr(new_path, OS_PATH_SEPARATOR) != NULL);
retry:
count++;
if (!(count % 1000)) {
- ib::warn() << "Cannot rename " << old_path << " to "
- << new_path << ", retried " << count << " times."
+ ib::warn() << "Cannot rename file " << old_path
+ << " (space id " << id << "), retried " << count
+ << " times."
" There are either pending IOs or flushes or"
" the file is being extended.";
}
@@ -3269,8 +3263,6 @@ retry:
space = fil_space_get_by_id(id);
- bool success = false;
-
DBUG_EXECUTE_IF("fil_rename_tablespace_failure_1", space = NULL; );
if (space == NULL) {
@@ -3278,11 +3270,25 @@ retry:
<< " in the tablespace memory cache, though the file '"
<< old_path
<< "' in a rename operation should have that id.";
+func_exit:
+ mutex_exit(&fil_system->mutex);
+ return(false);
+ }
+ if (count > 25000) {
+ space->stop_ios = false;
+ goto func_exit;
+ }
+ if (space != fil_space_get_by_name(space->name)) {
+ ib::error() << "Cannot find " << space->name
+ << " in tablespace memory cache";
+ space->stop_ios = false;
goto func_exit;
}
- if (count > 25000) {
+ if (fil_space_get_by_name(new_name)) {
+ ib::error() << new_name
+ << " is already in tablespace memory cache";
space->stop_ios = false;
goto func_exit;
}
@@ -3305,21 +3311,18 @@ retry:
currently being extended, sleep for a while and
retry */
sleep = true;
-
} else if (node->modification_counter > node->flush_counter) {
/* Flush the space */
sleep = flush = true;
-
} else if (node->is_open) {
/* Close the file */
fil_node_close_file(node);
}
- if (sleep) {
-
- mutex_exit(&fil_system->mutex);
+ mutex_exit(&fil_system->mutex);
+ if (sleep) {
os_thread_sleep(20000);
if (flush) {
@@ -3329,56 +3332,83 @@ retry:
sleep = flush = false;
goto retry;
}
+ ut_ad(space->stop_ios);
+ char* new_file_name = new_path_in == NULL
+ ? fil_make_filepath(NULL, new_name, IBD, false)
+ : mem_strdup(new_path_in);
+ char* old_file_name = node->name;
+ char* new_space_name = mem_strdup(new_name);
+ char* old_space_name = space->name;
+ ulint old_fold = ut_fold_string(old_space_name);
+ ulint new_fold = ut_fold_string(new_space_name);
+
+ ut_ad(strchr(old_file_name, OS_PATH_SEPARATOR) != NULL);
+ ut_ad(strchr(new_file_name, OS_PATH_SEPARATOR) != NULL);
+#ifndef UNIV_HOTBACKUP
+ if (!recv_recovery_on) {
+ mtr_t mtr;
- old_name = mem_strdup(space->name);
+ mtr.start();
+ fil_name_write_rename(
+ id, 0, old_file_name, new_file_name, &mtr);
+ mtr.commit();
+ log_mutex_enter();
+ }
+#endif /* !UNIV_HOTBACKUP */
- /* Rename the tablespace and the node in the memory cache */
- success = fil_rename_tablespace_in_mem(
- space, node, new_name, new_path);
+ /* log_sys->mutex is above fil_system->mutex in the latching order */
+ ut_ad(log_mutex_own());
+ mutex_enter(&fil_system->mutex);
+ ut_ad(space->name == old_space_name);
+ /* We already checked these. */
+ ut_ad(space == fil_space_get_by_name(old_space_name));
+ ut_ad(!fil_space_get_by_name(new_space_name));
+ ut_ad(node->name == old_file_name);
- if (success) {
+ bool success;
- DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
- goto skip_second_rename; );
+ DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
+ goto skip_rename; );
- success = os_file_rename(
- innodb_data_file_key, old_path, new_path);
+ success = os_file_rename(
+ innodb_data_file_key, old_file_name, new_file_name);
- DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
-skip_second_rename:
- success = false; );
+ DBUG_EXECUTE_IF("fil_rename_tablespace_failure_2",
+ skip_rename: success = false; );
- if (!success) {
- /* We have to revert the changes we made
- to the tablespace memory cache */
+ ut_ad(node->name == old_file_name);
- bool reverted = fil_rename_tablespace_in_mem(
- space, node, old_name, old_path);
-
- ut_a(reverted);
- }
+ if (success) {
+ node->name = new_file_name;
}
- ut_free(old_name);
- space->stop_ios = false;
-
-func_exit:
- mutex_exit(&fil_system->mutex);
-
#ifndef UNIV_HOTBACKUP
- if (success && !recv_recovery_on) {
- mtr_t mtr;
-
- mtr_start(&mtr);
- fil_name_write_rename(id, 0, old_path, new_path, &mtr);
- mtr_commit(&mtr);
+ if (!recv_recovery_on) {
+ log_mutex_exit();
}
#endif /* !UNIV_HOTBACKUP */
- if (new_path != new_path_in) {
- ut_free(const_cast<char*>(new_path));
+ ut_ad(space->name == old_space_name);
+ if (success) {
+ HASH_DELETE(fil_space_t, name_hash, fil_system->name_hash,
+ old_fold, space);
+ space->name = new_space_name;
+ HASH_INSERT(fil_space_t, name_hash, fil_system->name_hash,
+ new_fold, space);
+ } else {
+ /* Because nothing was renamed, we must free the new
+ names, not the old ones. */
+ old_file_name = new_file_name;
+ old_space_name = new_space_name;
}
+ ut_ad(space->stop_ios);
+ space->stop_ios = false;
+ mutex_exit(&fil_system->mutex);
+
+ ut_free(old_file_name);
+ ut_free(old_space_name);
+
return(success);
}
@@ -3388,8 +3418,10 @@ func_exit:
For general tablespaces, the 'dbname/' part may be missing.
@param[in] path Path and filename of the datafile to create.
@param[in] flags Tablespace flags
-@param[in] size Initial size of the tablespace file in pages,
-must be >= FIL_IBD_FILE_INITIAL_SIZE
+@param[in] size Initial size of the tablespace file in
+ pages, must be >= FIL_IBD_FILE_INITIAL_SIZE
+@param[in] mode MariaDB encryption mode
+@param[in] key_id MariaDB encryption key_id
@return DB_SUCCESS or error code */
dberr_t
fil_ibd_create(
@@ -3398,8 +3430,8 @@ fil_ibd_create(
const char* path,
ulint flags,
ulint size,
- fil_encryption_t mode, /*!< in: encryption mode */
- ulint key_id) /*!< in: encryption key_id */
+ fil_encryption_t mode,
+ ulint key_id)
{
os_file_t file;
dberr_t err;
@@ -3411,7 +3443,7 @@ fil_ibd_create(
bool has_shared_space = FSP_FLAGS_GET_SHARED(flags);
fil_space_t* space = NULL;
fil_space_crypt_t *crypt_data = NULL;
-
+
ut_ad(!is_system_tablespace(space_id));
ut_ad(!srv_read_only_mode);
ut_a(space_id < SRV_LOG_SPACE_FIRST_ID);
@@ -3547,10 +3579,11 @@ fil_ibd_create(
page = static_cast<byte*>(ut_align(buf2, UNIV_PAGE_SIZE));
memset(page, '\0', UNIV_PAGE_SIZE);
-
+#ifndef UNIV_HOTBACKUP
/* Add the UNIV_PAGE_SIZE to the table flags and write them to the
tablespace header. */
flags = fsp_flags_set_page_size(flags, univ_page_size);
+#endif /* !UNIV_HOTBACKUP */
fsp_header_init_fields(page, space_id, flags);
mach_write_to_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID, space_id);
@@ -3570,7 +3603,6 @@ fil_ibd_create(
} else {
page_zip_des_t page_zip;
-
page_zip_set_size(&page_zip, page_size.physical());
page_zip.data = page + UNIV_PAGE_SIZE;
#ifdef UNIV_DEBUG
@@ -3616,6 +3648,9 @@ fil_ibd_create(
return(DB_ERROR);
}
+ /* MEB creates isl files during copy-back, hence they
+ should not be created during apply log operation. */
+#ifndef UNIV_HOTBACKUP
if (has_data_dir || has_shared_space) {
/* Make the ISL file if the IBD file is not
in the default location. */
@@ -3627,6 +3662,7 @@ fil_ibd_create(
return(err);
}
}
+#endif /* !UNIV_HOTBACKUP */
/* Create crypt data if the tablespace is either encrypted or user has
requested it to remain unencrypted. */
@@ -3636,15 +3672,31 @@ fil_ibd_create(
}
space = fil_space_create(name, space_id, flags, is_temp
- ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE, crypt_data);
+ ? FIL_TYPE_TEMPORARY : FIL_TYPE_TABLESPACE,
+ crypt_data);
if (!fil_node_create_low(
path, size, space, false, punch_hole, atomic_write)) {
+ if (crypt_data) {
+ free(crypt_data);
+ }
+
err = DB_ERROR;
goto error_exit_1;
}
+#ifdef MYSQL_ENCRYPTION
+ /* For encryption tablespace, initial encryption information. */
+ if (FSP_FLAGS_GET_ENCRYPTION(space->flags)) {
+ err = fil_set_encryption(space->id,
+ Encryption::AES,
+ NULL,
+ NULL);
+ ut_ad(err == DB_SUCCESS);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
#ifndef UNIV_HOTBACKUP
if (!is_temp) {
mtr_t mtr;
@@ -3657,7 +3709,7 @@ fil_ibd_create(
fil_name_write(space, 0, file, &mtr);
mtr_commit(&mtr);
}
-#endif
+#endif /* !UNIV_HOTBACKUP */
err = DB_SUCCESS;
/* Error code is set. Cleanup the various variables used.
@@ -3715,18 +3767,20 @@ fil_ibd_open(
ulint flags,
const char* space_name,
const char* path_in,
- dict_table_t* table)
+ dict_table_t* table)
{
dberr_t err = DB_SUCCESS;
bool dict_filepath_same_as_default = false;
bool link_file_found = false;
bool link_file_is_bad = false;
bool is_shared = FSP_FLAGS_GET_SHARED(flags);
+ bool is_encrypted = FSP_FLAGS_GET_ENCRYPTION(flags);
Datafile df_default; /* default location */
Datafile df_dict; /* dictionary location */
RemoteDatafile df_remote; /* remote location */
ulint tablespaces_found = 0;
ulint valid_tablespaces_found = 0;
+ bool for_import = (purpose == FIL_TYPE_IMPORT);
ut_ad(!fix_dict || rw_lock_own(dict_operation_lock, RW_LOCK_X));
@@ -3778,7 +3832,6 @@ fil_ibd_open(
if (table) {
table->crypt_data = df_remote.get_crypt_info();
}
-
} else if (df_remote.filepath() != NULL) {
/* An ISL file was found but contained a bad filepath in it.
Better validate anything we do find. */
@@ -3793,7 +3846,6 @@ fil_ibd_open(
/* Dict path is not the default path. Always validate
remote files. If default is opened, it was moved. */
validate = true;
-
df_dict.set_filepath(path_in);
if (df_dict.open_read_only(true) == DB_SUCCESS) {
ut_ad(df_dict.is_open());
@@ -3839,7 +3891,6 @@ fil_ibd_open(
#if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
if (!srv_use_doublewrite_buf && df_default.is_open()) {
-
atomic_write = fil_fusionio_enable_atomic_write(
df_default.handle());
} else {
@@ -3852,31 +3903,46 @@ fil_ibd_open(
/* We have now checked all possible tablespace locations and
have a count of how many unique files we found. If things are
normal, we only found 1. */
- if (!validate && tablespaces_found == 1) {
+ /* For encrypted tablespace, we need to check the
+ encryption in header of first page. */
+ if (!validate && tablespaces_found == 1 && !is_encrypted) {
goto skip_validate;
}
/* Read and validate the first page of these three tablespace
locations, if found. */
valid_tablespaces_found +=
- (df_remote.validate_to_dd(id, flags) == DB_SUCCESS) ? 1 : 0;
+ (df_remote.validate_to_dd(id, flags, for_import)
+ == DB_SUCCESS) ? 1 : 0;
valid_tablespaces_found +=
- (df_default.validate_to_dd(id, flags) == DB_SUCCESS) ? 1 : 0;
+ (df_default.validate_to_dd(id, flags, for_import)
+ == DB_SUCCESS) ? 1 : 0;
valid_tablespaces_found +=
- (df_dict.validate_to_dd(id, flags) == DB_SUCCESS) ? 1 : 0;
+ (df_dict.validate_to_dd(id, flags, for_import)
+ == DB_SUCCESS) ? 1 : 0;
/* Make sense of these three possible locations.
First, bail out if no tablespace files were found. */
if (valid_tablespaces_found == 0) {
- /* The following call prints an error message */
- os_file_get_last_error(true);
- ib::error() << "Could not find a valid tablespace file for `"
- << space_name << "`. " << TROUBLESHOOT_DATADICT_MSG;
+ if (!is_encrypted) {
+ /* The following call prints an error message.
+ For encrypted tablespace we skip print, since it should
+ be keyring plugin issues. */
+ os_file_get_last_error(true);
+ ib::error() << "Could not find a valid tablespace file for `"
+ << space_name << "`. " << TROUBLESHOOT_DATADICT_MSG;
+ }
return(DB_CORRUPTION);
}
+ if (!validate && !is_encrypted) {
+ return(DB_SUCCESS);
+ }
+ if (validate && is_encrypted && fil_space_get(id)) {
+ return(DB_SUCCESS);
+ }
/* Do not open any tablespaces if more than one tablespace with
the correct space ID and flags were found. */
@@ -4024,10 +4090,10 @@ fil_ibd_open(
skip_validate:
if (err == DB_SUCCESS) {
fil_space_t* space = fil_space_create(
- space_name, id, flags, purpose,
- df_remote.is_open() ? df_remote.get_crypt_info() :
- df_dict.is_open() ? df_dict.get_crypt_info() :
- df_default.get_crypt_info());
+ space_name, id, flags, purpose,
+ df_remote.is_open() ? df_remote.get_crypt_info() :
+ df_dict.is_open() ? df_dict.get_crypt_info() :
+ df_default.get_crypt_info());
/* We do not measure the size of the file, that is why
we pass the 0 below */
@@ -4037,9 +4103,27 @@ skip_validate:
df_dict.is_open() ? df_dict.filepath() :
df_default.filepath(), 0, space, false,
true, atomic_write) == NULL) {
-
err = DB_ERROR;
}
+
+#ifdef MYSQL_ENCRYPTION
+ /* For encryption tablespace, initialize encryption
+ information.*/
+ if (err == DB_SUCCESS && is_encrypted && !for_import) {
+ Datafile& df_current = df_remote.is_open() ?
+ df_remote: df_dict.is_open() ?
+ df_dict : df_default;
+
+ byte* key = df_current.m_encryption_key;
+ byte* iv = df_current.m_encryption_iv;
+ ut_ad(key && iv);
+
+ err = fil_set_encryption(space->id, Encryption::AES,
+ key, iv);
+ ut_ad(err == DB_SUCCESS);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
}
return(err);
@@ -4296,7 +4380,6 @@ fil_ibd_discover(
/* A datafile was not discovered for the filename given. */
return(false);
}
-
/** Open an ibd tablespace and add it to the InnoDB data structures.
This is similar to fil_ibd_open() except that it is used while processing
the REDO log, so the data dictionary is not available and very little
@@ -4327,14 +4410,17 @@ fil_ibd_load(
filename from the first node of the tablespace we opened
previously. Fail if it is different. */
fil_node_t* node = UT_LIST_GET_FIRST(space->chain);
-
if (0 != strcmp(innobase_basename(filename),
innobase_basename(node->name))) {
- ib::info() << "Ignoring data file '" << filename
+#ifdef UNIV_HOTBACKUP
+ ib::trace()
+#else
+ ib::info()
+#endif /* UNIV_HOTBACKUP */
+ << "Ignoring data file '" << filename
<< "' with space ID " << space->id
<< ". Another data file called " << node->name
<< " exists with the same space ID.";
-
space = NULL;
return(FIL_LOAD_ID_CHANGED);
}
@@ -4345,7 +4431,6 @@ fil_ibd_load(
under the datadir, then just try to open it there. */
Datafile file;
file.set_filepath(filename);
-
Folder folder(filename, dirname_length(filename));
if (folder_mysql_datadir >= folder) {
file.open_read_only(false);
@@ -4367,7 +4452,12 @@ fil_ibd_load(
os_offset_t minimum_size;
case DB_SUCCESS:
if (file.space_id() != space_id) {
- ib::info() << "Ignoring data file '"
+#ifdef UNIV_HOTBACKUP
+ ib::trace()
+#else /* !UNIV_HOTBACKUP */
+ ib::info()
+#endif /* UNIV_HOTBACKUP */
+ << "Ignoring data file '"
<< file.filepath()
<< "' with space ID " << file.space_id()
<< ", since the redo log references "
@@ -4375,7 +4465,6 @@ fil_ibd_load(
<< space_id << ".";
return(FIL_LOAD_ID_CHANGED);
}
-
/* Get and test the file size. */
size = os_file_get_size(file.handle());
@@ -4390,7 +4479,6 @@ fil_ibd_load(
ib::error() << "Could not measure the size of"
" single-table tablespace file '"
<< file.filepath() << "'";
-
} else if (size < minimum_size) {
#ifndef UNIV_HOTBACKUP
ib::error() << "The size of tablespace file '"
@@ -4411,6 +4499,12 @@ fil_ibd_load(
/* Fall through to error handling */
case DB_TABLESPACE_EXISTS:
+#ifdef UNIV_HOTBACKUP
+ if (file.flags() == ~(ulint)0) {
+ return FIL_LOAD_OK;
+ }
+#endif /* UNIV_HOTBACKUP */
+
return(FIL_LOAD_INVALID);
default:
@@ -4499,6 +4593,21 @@ fil_ibd_load(
ut_error;
}
+#ifdef MYSQL_ENCRYPTION
+ /* For encryption tablespace, initial encryption information. */
+ if (FSP_FLAGS_GET_ENCRYPTION(space->flags)
+ && file.m_encryption_key != NULL) {
+ dberr_t err = fil_set_encryption(space->id,
+ Encryption::AES,
+ file.m_encryption_key,
+ file.m_encryption_iv);
+ if (err != DB_SUCCESS) {
+ ib::error() << "Can't set encryption information for"
+ " tablespace " << space->name << "!";
+ }
+ }
+#endif /* MYSQL_ENCRYPTION */
+
return(FIL_LOAD_OK);
}
@@ -4556,6 +4665,7 @@ fil_report_missing_tablespace(
" exists in the InnoDB internal data dictionary.";
}
+#ifndef UNIV_HOTBACKUP
/** Returns true if a matching tablespace exists in the InnoDB tablespace
memory cache. Note that if we have not done a crash recovery at the database
startup, there may be many tablespaces which are not yet in the memory cache.
@@ -4567,6 +4677,7 @@ error log if a matching tablespace is not found from memory.
@param[in] adjust_space Whether to adjust space id on mismatch
@param[in] heap Heap memory
@param[in] table_id table id
+@param[in] table table
@return true if a matching tablespace exists in the memory cache */
bool
fil_space_for_table_exists_in_mem(
@@ -4633,7 +4744,6 @@ fil_space_for_table_exists_in_mem(
/* Found */
mutex_exit(&fil_system->mutex);
-
return(true);
}
}
@@ -4732,7 +4842,7 @@ error_exit:
return(false);
}
-
+#endif /* !UNIV_HOTBACKUP */
/** Return the space ID based on the tablespace name.
The tablespace must be found in the tablespace memory cache.
This call is made from external to this module, so the mutex is not owned.
@@ -4787,7 +4897,7 @@ fil_write_zeros(
while (offset < end) {
#ifdef UNIV_HOTBACKUP
- err = = os_file_write(
+ err = os_file_write(
request, node->name, node->handle, buf, offset,
n_bytes);
#else
@@ -4828,6 +4938,16 @@ fil_space_extend(
ut_ad(!srv_read_only_mode || fsp_is_system_temporary(space->id));
retry:
+
+#ifdef UNIV_HOTBACKUP
+ page_size_t page_length(space->flags);
+ ulint actual_size = space->size;
+ ib::trace() << "space id : " << space->id << ", space name : "
+ << space->name << ", space size : " << actual_size << " pages,"
+ << " desired space size : " << size << " pages,"
+ << " page size : " << page_length.physical();
+#endif /* UNIV_HOTBACKUP */
+
bool success = true;
fil_mutex_enter_and_prepare_for_io(space->id);
@@ -4905,14 +5025,12 @@ retry:
len = ((node->size + n_node_extend) * page_size) - node_start;
ut_ad(len > 0);
+ const char* name = node->name == NULL ? space->name : node->name;
#if !defined(NO_FALLOCATE) && defined(UNIV_LINUX)
/* This is required by FusionIO HW/Firmware */
int ret = posix_fallocate(node->handle, node_start, len);
- const char* name = node->name == NULL ? space->name : node->name;
-
-
/* We already pass the valid offset and len in, if EINVAL
is returned, it could only mean that the file system doesn't
support fallocate(), currently one known case is
@@ -4922,7 +5040,7 @@ retry:
ib::error()
<< "posix_fallocate(): Failed to preallocate"
" data for file "
- << node->name << ", desired size "
+ << name << ", desired size "
<< len << " bytes."
" Operating system error number "
<< ret << ". Check"
@@ -4951,7 +5069,7 @@ retry:
ib::warn()
<< "Error while writing " << len
- << " zeroes to " << node->name
+ << " zeroes to " << name
<< " starting at offset " << node_start;
}
}
@@ -4991,6 +5109,10 @@ retry:
} else if (space->id == srv_tmp_space.space_id()) {
srv_tmp_space.set_last_file_size(size_in_pages);
}
+#else
+ ib::trace() << "extended space : " << space->name << " from "
+ << actual_size << " pages to " << space->size << " pages "
+ << ", desired space size : " << size << " pages.";
#endif /* !UNIV_HOTBACKUP */
mutex_exit(&fil_system->mutex);
@@ -5016,7 +5138,7 @@ fil_extend_tablespaces_to_stored_len(void)
dberr_t error;
bool success;
- buf = ut_malloc_nokey(UNIV_PAGE_SIZE);
+ buf = (byte*)ut_malloc_nokey(UNIV_PAGE_SIZE);
mutex_enter(&fil_system->mutex);
@@ -5273,6 +5395,33 @@ fil_report_invalid_page_access(
_exit(1);
}
+#ifdef MYSQL_ENCRYPTION
+/** Set encryption information for IORequest.
+@param[in,out] req_type IO request
+@param[in] page_id page id
+@param[in] space table space */
+inline
+void
+fil_io_set_encryption(
+ IORequest& req_type,
+ const page_id_t& page_id,
+ fil_space_t* space)
+{
+ /* Don't encrypt the log, page 0 of all tablespaces, all pages
+ from the system tablespace. */
+ if (!req_type.is_log() && page_id.page_no() > 0
+ && space->encryption_type != Encryption::NONE)
+ {
+ req_type.encryption_key(space->encryption_key,
+ space->encryption_klen,
+ space->encryption_iv);
+ req_type.encryption_algorithm(Encryption::AES);
+ } else {
+ req_type.clear_encrypted();
+ }
+}
+#endif /* MYSQL_ENCRYPTION */
+
/** Reads or writes data. This operation could be asynchronous (aio).
@param[in,out] type IO context
@@ -5289,7 +5438,8 @@ fil_report_invalid_page_access(
aligned
@param[in] message message for aio handler if non-sync aio
used, else ignored
-
+@param[in] write_size actual payload size when written
+ to avoid extra punch holes in compression
@return DB_SUCCESS, DB_TABLESPACE_DELETED or DB_TABLESPACE_TRUNCATED
if we are trying to do i/o on a tablespace which does not exist */
dberr_t
@@ -5355,9 +5505,10 @@ fil_io(
}
#else /* !UNIV_HOTBACKUP */
ut_a(sync);
- mode = OS_AIO_SYNC;
+ ulint mode = OS_AIO_SYNC;
#endif /* !UNIV_HOTBACKUP */
+#ifndef UNIV_HOTBACKUP
if (req_type.is_read()) {
srv_stats.data_read.add(len);
@@ -5369,6 +5520,7 @@ fil_io(
srv_stats.data_written.add(len);
}
+#endif /* !UNIV_HOTBACKUP */
/* Reserve the fil_system mutex and make sure that we can open at
least one file while holding it, if the file is not already open */
@@ -5434,7 +5586,7 @@ fil_io(
&& UT_LIST_GET_LEN(space->chain) == 1
&& (srv_is_tablespace_truncated(space->id)
|| space->is_being_truncated
- || srv_was_tablespace_truncated(space->id))
+ || srv_was_tablespace_truncated(space))
&& req_type.is_read()) {
/* Handle page which is outside the truncated
@@ -5541,6 +5693,7 @@ fil_io(
const char* name = node->name == NULL ? space->name : node->name;
+#ifdef MYSQL_COMPRESSION
/* Don't compress the log, page 0 of all tablespaces, tables
compresssed with the old scheme and all pages from the system
tablespace. */
@@ -5561,6 +5714,12 @@ fil_io(
} else {
req_type.clear_compressed();
}
+#endif /* MYSQL_COMPRESSION */
+
+#ifdef MYSQL_ENCRYPTION
+ /* Set encryption information. */
+ fil_io_set_encryption(req_type, page_id, space);
+#endif /* MYSQL_ENCRYPTION */
req_type.block_size(node->block_size);
@@ -5580,14 +5739,14 @@ fil_io(
err = os_file_write(
req_type, node->name, node->handle, buf, offset, len);
}
-#else
+#else /* UNIV_HOTBACKUP */
/* Queue the aio request */
err = os_aio(
req_type,
- mode, node->name, node->handle, buf, offset, len,
+ mode, name, node->handle, buf, offset, len,
fsp_is_system_temporary(page_id.space())
? false : srv_read_only_mode,
- node, message, NULL);
+ node, message, write_size);
#endif /* UNIV_HOTBACKUP */
@@ -5599,7 +5758,7 @@ fil_io(
ib::warn()
<< "Punch hole failed for '"
- << node->name << "'";
+ << name << "'";
}
fil_no_punch_hole(node);
@@ -5689,7 +5848,7 @@ fil_aio_wait(
ut_ad(0);
}
-#endif /* UNIV_HOTBACKUP */
+#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
Flushes to disk possible writes cached by the OS. If the space does not exist
@@ -5777,7 +5936,9 @@ retry:
not know what bugs OS's may contain in file
i/o */
+#ifndef UNIV_HOTBACKUP
int64_t sig_count = os_event_reset(node->sync_event);
+#endif /* !UNIV_HOTBACKUP */
mutex_exit(&fil_system->mutex);
@@ -6020,6 +6181,7 @@ fil_page_set_type(
mach_write_to_2(page + FIL_PAGE_TYPE, type);
}
+#ifndef UNIV_HOTBACKUP
/** Reset the page type.
Data files created before MySQL 5.1 may contain garbage in FIL_PAGE_TYPE.
In MySQL 3.23.53, only undo log pages and index pages were tagged.
@@ -6040,6 +6202,7 @@ fil_page_reset_type(
<< fil_page_get_type(page) << " to " << type << ".";
mlog_write_ulint(page + FIL_PAGE_TYPE, type, MLOG_2BYTES, mtr);
}
+#endif /* !UNIV_HOTBACKUP */
/****************************************************************//**
Closes the tablespace memory cache. */
@@ -6047,20 +6210,23 @@ void
fil_close(void)
/*===========*/
{
- hash_table_free(fil_system->spaces);
+ if (fil_system) {
+ hash_table_free(fil_system->spaces);
- hash_table_free(fil_system->name_hash);
+ hash_table_free(fil_system->name_hash);
- ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0);
- ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0);
- ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0);
+ ut_a(UT_LIST_GET_LEN(fil_system->LRU) == 0);
+ ut_a(UT_LIST_GET_LEN(fil_system->unflushed_spaces) == 0);
+ ut_a(UT_LIST_GET_LEN(fil_system->space_list) == 0);
- mutex_free(&fil_system->mutex);
+ mutex_free(&fil_system->mutex);
- ut_free(fil_system);
- fil_system = NULL;
+ ut_free(fil_system);
+ fil_system = NULL;
+ }
}
+#ifndef UNIV_HOTBACKUP
/********************************************************************//**
Initializes a buffer control block when the buf_pool is created. */
static
@@ -6092,8 +6258,10 @@ struct fil_iterator_t {
ulint n_io_buffers; /*!< Number of pages to use
for IO */
byte* io_buffer; /*!< Buffer to use for IO */
- fil_space_crypt_t *crypt_data; /*!< Crypt data (if encrypted) */
- byte* crypt_io_buffer; /*!< IO buffer when encrypted */
+ fil_space_crypt_t *crypt_data; /*!< MariaDB Crypt data (if encrypted) */
+ byte* crypt_io_buffer; /*!< MariaDB IO buffer when encrypted */
+ byte* encryption_key; /*!< Encryption key */
+ byte* encryption_iv; /*!< Encryption iv */
};
/********************************************************************//**
@@ -6166,9 +6334,19 @@ fil_iterate(
ut_ad(n_bytes > 0);
ut_ad(!(n_bytes % iter.page_size));
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
IORequest read_request(read_type);
+#ifdef MYSQL_ENCRYPTION
+ /* For encrypted table, set encryption information. */
+ if (iter.encryption_key != NULL && offset != 0) {
+ read_request.encryption_key(iter.encryption_key,
+ ENCRYPTION_KEY_LEN,
+ iter.encryption_iv);
+ read_request.encryption_algorithm(Encryption::AES);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
byte* readptr = io_buffer;
byte* writeptr = io_buffer;
bool encrypted = false;
@@ -6206,8 +6384,9 @@ fil_iterate(
ulint page_type = mach_read_from_2(src+FIL_PAGE_TYPE);
- bool page_compressed = (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED ||
- page_type == FIL_PAGE_PAGE_COMPRESSED);
+ bool page_compressed =
+ (page_type == FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED
+ || page_type == FIL_PAGE_PAGE_COMPRESSED);
/* If tablespace is encrypted, we need to decrypt
the page. */
@@ -6303,6 +6482,16 @@ fil_iterate(
IORequest write_request(write_type);
+#ifdef MYSQL_ENCRYPTION
+ /* For encrypted table, set encryption information. */
+ if (iter.encryption_key != NULL && offset != 0) {
+ write_request.encryption_key(iter.encryption_key,
+ ENCRYPTION_KEY_LEN,
+ iter.encryption_iv);
+ write_request.encryption_algorithm(Encryption::AES);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
/* A page was updated in the set, write back to disk.
Note: We don't have the compression algorithm, we write
out the imported file as uncompressed. */
@@ -6451,34 +6640,58 @@ fil_tablespace_iterate(
iter.crypt_data = fil_space_read_crypt_data(
0, page, crypt_data_offset);
- /* Compressed pages can't be optimised for block IO for now.
- We do the IMPORT page by page. */
-
- if (callback.get_page_size().is_compressed()) {
- iter.n_io_buffers = 1;
- ut_a(iter.page_size
- == callback.get_page_size().physical());
+#ifdef MYSQL_ENCRYPTION
+ /* Set encryption info. */
+ iter.encryption_key = table->encryption_key;
+ iter.encryption_iv = table->encryption_iv;
+
+ /* Check encryption is matched or not. */
+ ulint space_flags = callback.get_space_flags();
+ if (FSP_FLAGS_GET_ENCRYPTION(space_flags)) {
+ ut_ad(table->encryption_key != NULL);
+
+ if (!dict_table_is_encrypted(table)) {
+ ib::error() << "Table is not in an encrypted"
+ " tablespace, but the data file which"
+ " trying to import is an encrypted"
+ " tablespace";
+ err = DB_IO_NO_ENCRYPT_TABLESPACE;
+ }
}
+#endif /* MYSQL_ENCRYPTION */
- /** Add an extra page for compressed page scratch area. */
+ if (err == DB_SUCCESS) {
- void* io_buffer = ut_malloc_nokey(
- (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
+ /* Compressed pages can't be optimised for block IO
+ for now. We do the IMPORT page by page. */
- iter.io_buffer = static_cast<byte*>(
- ut_align(io_buffer, UNIV_PAGE_SIZE));
+ if (callback.get_page_size().is_compressed()) {
+ iter.n_io_buffers = 1;
+ ut_a(iter.page_size
+ == callback.get_page_size().physical());
+ }
- void* crypt_io_buffer = NULL;
- if (iter.crypt_data != NULL) {
- crypt_io_buffer = ut_malloc_nokey(
- iter.n_io_buffers * UNIV_PAGE_SIZE);
- iter.crypt_io_buffer = static_cast<byte*>(
- crypt_io_buffer);
- }
+ /** Add an extra page for compressed page scratch
+ area. */
+ void* io_buffer = ut_malloc_nokey(
+ (2 + iter.n_io_buffers) * UNIV_PAGE_SIZE);
+
+ iter.io_buffer = static_cast<byte*>(
+ ut_align(io_buffer, UNIV_PAGE_SIZE));
+
+ /** Add an exta buffer for encryption */
+ void* crypt_io_buffer = NULL;
+ if (iter.crypt_data != NULL) {
+ crypt_io_buffer = ut_malloc_nokey(
+ iter.n_io_buffers * UNIV_PAGE_SIZE);
+ iter.crypt_io_buffer = static_cast<byte*>(
+ crypt_io_buffer);
+ }
- err = fil_iterate(iter, block, callback);
+ err = fil_iterate(iter, block, callback);
- ut_free(io_buffer);
+ ut_free(io_buffer);
+ }
}
if (err == DB_SUCCESS) {
@@ -6504,6 +6717,7 @@ fil_tablespace_iterate(
return(err);
}
+#endif /* !UNIV_HOTBACKUP */
/** Set the tablespace table size.
@param[in] page a page belonging to the tablespace */
@@ -6526,7 +6740,6 @@ fil_delete_file(
/* Force a delete of any stale .ibd files that are lying around. */
ib::info() << "Deleting " << ibd_filepath;
-
os_file_delete_if_exists(innodb_data_file_key, ibd_filepath, NULL);
char* cfg_filepath = fil_make_filepath(
@@ -6583,6 +6796,7 @@ fil_get_space_names(
return(err);
}
+#ifndef UNIV_HOTBACKUP
/** Return the next fil_node_t in the current or next fil_space_t.
Once started, the caller must keep calling this until it returns NULL.
fil_space_acquire() and fil_space_release() are invoked here which
@@ -6644,51 +6858,100 @@ fil_node_next(
@param[in] new_table new table
@param[in] tmp_name temporary table name
@param[in,out] mtr mini-transaction
-@return whether the operation succeeded */
-bool
+@return innodb error code */
+dberr_t
fil_mtr_rename_log(
const dict_table_t* old_table,
const dict_table_t* new_table,
const char* tmp_name,
mtr_t* mtr)
{
+ dberr_t err;
+
+ bool old_is_file_per_table =
+ !is_system_tablespace(old_table->space)
+ && !DICT_TF_HAS_SHARED_SPACE(old_table->flags);
+
+ bool new_is_file_per_table =
+ !is_system_tablespace(new_table->space)
+ && !DICT_TF_HAS_SHARED_SPACE(new_table->flags);
+
+ /* If neither table is file-per-table,
+ there will be no renaming of files. */
+ if (!old_is_file_per_table && !new_is_file_per_table) {
+ return(DB_SUCCESS);
+ }
+
const char* old_dir = DICT_TF_HAS_DATA_DIR(old_table->flags)
? old_table->data_dir_path
: NULL;
- const char* new_dir = DICT_TF_HAS_DATA_DIR(new_table->flags)
- ? new_table->data_dir_path
- : NULL;
-
- char* old_path = fil_make_filepath(
- new_dir, old_table->name.m_name, IBD, false);
- char* new_path = fil_make_filepath(
- new_dir, new_table->name.m_name, IBD, false);
- char* tmp_path = fil_make_filepath(
- old_dir, tmp_name, IBD, false);
- if (!old_path || !new_path || !tmp_path) {
- ut_free(old_path);
- ut_free(new_path);
- ut_free(tmp_path);
- return(false);
+ char* old_path = fil_make_filepath(
+ old_dir, old_table->name.m_name, IBD, (old_dir != NULL));
+ if (old_path == NULL) {
+ return(DB_OUT_OF_MEMORY);
}
- if (!is_system_tablespace(old_table->space)) {
+ if (old_is_file_per_table) {
+ char* tmp_path = fil_make_filepath(
+ old_dir, tmp_name, IBD, (old_dir != NULL));
+ if (tmp_path == NULL) {
+ ut_free(old_path);
+ return(DB_OUT_OF_MEMORY);
+ }
+
+ /* Temp filepath must not exist. */
+ err = fil_rename_tablespace_check(
+ old_table->space, old_path, tmp_path,
+ dict_table_is_discarded(old_table));
+ if (err != DB_SUCCESS) {
+ ut_free(old_path);
+ ut_free(tmp_path);
+ return(err);
+ }
+
fil_name_write_rename(
old_table->space, 0, old_path, tmp_path, mtr);
+
+ ut_free(tmp_path);
}
- if (!is_system_tablespace(new_table->space)) {
+ if (new_is_file_per_table) {
+ const char* new_dir = DICT_TF_HAS_DATA_DIR(new_table->flags)
+ ? new_table->data_dir_path
+ : NULL;
+ char* new_path = fil_make_filepath(
+ new_dir, new_table->name.m_name,
+ IBD, (new_dir != NULL));
+ if (new_path == NULL) {
+ ut_free(old_path);
+ return(DB_OUT_OF_MEMORY);
+ }
+
+ /* Destination filepath must not exist unless this ALTER
+ TABLE starts and ends with a file_per-table tablespace. */
+ if (!old_is_file_per_table) {
+ err = fil_rename_tablespace_check(
+ new_table->space, new_path, old_path,
+ dict_table_is_discarded(new_table));
+ if (err != DB_SUCCESS) {
+ ut_free(old_path);
+ ut_free(new_path);
+ return(err);
+ }
+ }
+
fil_name_write_rename(
new_table->space, 0, new_path, old_path, mtr);
+
+ ut_free(new_path);
}
ut_free(old_path);
- ut_free(new_path);
- ut_free(tmp_path);
- return(true);
-}
+ return(DB_SUCCESS);
+}
+#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_DEBUG
/** Check that a tablespace is valid for mtr_commit().
@param[in] space persistent tablespace that has been changed */
@@ -6770,13 +7033,13 @@ fil_names_dirty_and_write(
DBUG_EXECUTE_IF("fil_names_write_bogus",
{
char bogus_name[] = "./test/bogus file.ibd";
- os_normalize_path_for_win(bogus_name);
+ os_normalize_path(bogus_name);
fil_name_write(
SRV_LOG_SPACE_FIRST_ID, 0,
bogus_name, mtr);
});
}
-
+#ifndef UNIV_HOTBACKUP
/** On a log checkpoint, reset fil_names_dirty_and_write() flags
and write out MLOG_FILE_NAME and MLOG_CHECKPOINT if needed.
@param[in] lsn checkpoint LSN
@@ -6948,6 +7211,7 @@ truncate_t::truncate(
return(err);
}
+#endif /* !UNIV_HOTBACKUP */
/**
Note that the file system where the file resides doesn't support PUNCH HOLE.
@@ -6959,18 +7223,28 @@ fil_no_punch_hole(fil_node_t* node)
node->punch_hole = false;
}
-/** Set the compression type for the tablespace
-@param[in] space Space ID of tablespace for which to set
-@param[in] algorithm Text representation of the algorithm
+#ifdef MYSQL_COMPRESSION_ENCRYPTION
+
+/** Set the compression type for the tablespace of a table
+@param[in] table The table that should be compressed
+@param[in] algorithm Text representation of the algorithm
@return DB_SUCCESS or error code */
dberr_t
fil_set_compression(
- ulint space_id,
+ dict_table_t* table,
const char* algorithm)
{
- ut_ad(!is_system_or_undo_tablespace(space_id));
+ ut_ad(table != NULL);
- if (is_shared_tablespace(space_id)) {
+ /* We don't support Page Compression for the system tablespace,
+ the temporary tablespace, or any general tablespace because
+ COMPRESSION is set by TABLE DDL, not TABLESPACE DDL. There is
+ no other technical reason. Also, do not use it for missing
+ tables or tables with compressed row_format. */
+ if (table->ibd_file_missing
+ || !DICT_TF2_FLAG_IS_SET(table, DICT_TF2_USE_FILE_PER_TABLE)
+ || DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY)
+ || page_size_t(table->flags).is_compressed()) {
return(DB_IO_NO_PUNCH_HOLE_TABLESPACE);
}
@@ -6983,17 +7257,20 @@ fil_set_compression(
#ifndef UNIV_DEBUG
compression.m_type = Compression::NONE;
#else
- compression.m_type = static_cast<Compression::Type>(
- srv_debug_compress);
-
- switch (compression.m_type) {
+ /* This is a Debug tool for setting compression on all
+ compressible tables not otherwise specified. */
+ switch (srv_debug_compress) {
case Compression::LZ4:
- case Compression::NONE:
case Compression::ZLIB:
+ case Compression::NONE:
+
+ compression.m_type =
+ static_cast<Compression::Type>(
+ srv_debug_compress);
break;
default:
- ut_error;
+ compression.m_type = Compression::NONE;
}
#endif /* UNIV_DEBUG */
@@ -7003,31 +7280,25 @@ fil_set_compression(
} else {
err = Compression::check(algorithm, &compression);
-
- ut_ad(err == DB_SUCCESS || err == DB_UNSUPPORTED);
}
- fil_space_t* space = fil_space_get(space_id);
+ fil_space_t* space = fil_space_get(table->space);
if (space == NULL) {
+ return(DB_NOT_FOUND);
+ }
- err = DB_NOT_FOUND;
-
- } else {
-
- space->compression_type = compression.m_type;
+ space->compression_type = compression.m_type;
- if (space->compression_type != Compression::NONE
- && err == DB_SUCCESS) {
+ if (space->compression_type != Compression::NONE) {
- const fil_node_t* node;
+ const fil_node_t* node;
- node = UT_LIST_GET_FIRST(space->chain);
+ node = UT_LIST_GET_FIRST(space->chain);
- if (!node->punch_hole) {
+ if (!node->punch_hole) {
- return(DB_IO_NO_PUNCH_HOLE_FS);
- }
+ return(DB_IO_NO_PUNCH_HOLE_FS);
}
}
@@ -7046,6 +7317,102 @@ fil_get_compression(
return(space == NULL ? Compression::NONE : space->compression_type);
}
+/** Set the encryption type for the tablespace
+@param[in] space_id Space ID of tablespace for which to set
+@param[in] algorithm Encryption algorithm
+@param[in] key Encryption key
+@param[in] iv Encryption iv
+@return DB_SUCCESS or error code */
+dberr_t
+fil_set_encryption(
+ ulint space_id,
+ Encryption::Type algorithm,
+ byte* key,
+ byte* iv)
+{
+ ut_ad(!is_system_or_undo_tablespace(space_id));
+
+ if (is_system_tablespace(space_id)) {
+ return(DB_IO_NO_ENCRYPT_TABLESPACE);
+ }
+
+ mutex_enter(&fil_system->mutex);
+
+ fil_space_t* space = fil_space_get_by_id(space_id);
+
+ if (space == NULL) {
+ mutex_exit(&fil_system->mutex);
+ return(DB_NOT_FOUND);
+ }
+
+ ut_ad(algorithm != Encryption::NONE);
+ space->encryption_type = algorithm;
+ if (key == NULL) {
+ Encryption::random_value(space->encryption_key);
+ } else {
+ memcpy(space->encryption_key,
+ key, ENCRYPTION_KEY_LEN);
+ }
+
+ space->encryption_klen = ENCRYPTION_KEY_LEN;
+ if (iv == NULL) {
+ Encryption::random_value(space->encryption_iv);
+ } else {
+ memcpy(space->encryption_iv,
+ iv, ENCRYPTION_KEY_LEN);
+ }
+
+ mutex_exit(&fil_system->mutex);
+
+ return(DB_SUCCESS);
+}
+
+/** Rotate the tablespace keys by new master key.
+@return true if the re-encrypt suceeds */
+bool
+fil_encryption_rotate()
+{
+ fil_space_t* space;
+ mtr_t mtr;
+ byte encrypt_info[ENCRYPTION_INFO_SIZE_V2];
+
+ for (space = UT_LIST_GET_FIRST(fil_system->space_list);
+ space != NULL; ) {
+ /* Skip unencypted tablespaces. */
+ if (is_system_or_undo_tablespace(space->id)
+ || fsp_is_system_temporary(space->id)
+ || space->purpose == FIL_TYPE_LOG) {
+ space = UT_LIST_GET_NEXT(space_list, space);
+ continue;
+ }
+
+ if (space->encryption_type != Encryption::NONE) {
+ mtr_start(&mtr);
+ mtr.set_named_space(space->id);
+
+ space = mtr_x_lock_space(space->id, &mtr);
+
+ memset(encrypt_info, 0, ENCRYPTION_INFO_SIZE_V2);
+
+ if (!fsp_header_rotate_encryption(space,
+ encrypt_info,
+ &mtr)) {
+ mtr_commit(&mtr);
+ return(false);
+ }
+
+ mtr_commit(&mtr);
+ }
+
+ space = UT_LIST_GET_NEXT(space_list, space);
+ DBUG_EXECUTE_IF("ib_crash_during_rotation_for_encryption",
+ DBUG_SUICIDE(););
+ }
+
+ return(true);
+}
+#endif /* MYSQL_COMPRESSION_ENCRYPTION */
+
/** Build the basic folder name from the path and length provided
@param[in] path pathname (may also include the file basename)
@param[in] len length of the path, in bytes */
@@ -7203,6 +7570,7 @@ test_make_filepath()
path = MF("/this/is/a/path/with/a/filename", NULL, IBD, false); DISPLAY;
path = MF("/this/is/a/path/with/a/filename", NULL, ISL, false); DISPLAY;
path = MF("/this/is/a/path/with/a/filename", NULL, CFG, false); DISPLAY;
+ path = MF("/this/is/a/path/with/a/filename", NULL, CFP, false); DISPLAY;
path = MF("/this/is/a/path/with/a/filename.ibd", NULL, IBD, false); DISPLAY;
path = MF("/this/is/a/path/with/a/filename.ibd", NULL, IBD, false); DISPLAY;
path = MF("/this/is/a/path/with/a/filename.dat", NULL, IBD, false); DISPLAY;
@@ -7212,6 +7580,7 @@ test_make_filepath()
path = MF(NULL, "dbname/tablespacename", IBD, false); DISPLAY;
path = MF(NULL, "dbname/tablespacename", ISL, false); DISPLAY;
path = MF(NULL, "dbname/tablespacename", CFG, false); DISPLAY;
+ path = MF(NULL, "dbname/tablespacename", CFP, false); DISPLAY;
path = MF(NULL, "dbname\\tablespacename", NO_EXT, false); DISPLAY;
path = MF(NULL, "dbname\\tablespacename", IBD, false); DISPLAY;
path = MF("/this/is/a/path", "dbname/tablespacename", IBD, false); DISPLAY;
@@ -7226,6 +7595,43 @@ test_make_filepath()
#endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
/* @} */
+/** Release the reserved free extents.
+@param[in] n_reserved number of reserved extents */
+void
+fil_space_t::release_free_extents(ulint n_reserved)
+{
+ ut_ad(rw_lock_own(&latch, RW_LOCK_X));
+
+ ut_a(n_reserved_extents >= n_reserved);
+ n_reserved_extents -= n_reserved;
+}
+
+/******************************************************************
+Get crypt data for a tablespace */
+UNIV_INTERN
+fil_space_crypt_t*
+fil_space_get_crypt_data(
+/*=====================*/
+ ulint id) /*!< in: space id */
+{
+ fil_space_t* space;
+ fil_space_crypt_t* crypt_data = NULL;
+
+ ut_ad(fil_system);
+
+ mutex_enter(&fil_system->mutex);
+
+ space = fil_space_get_by_id(id);
+
+ if (space != NULL) {
+ crypt_data = space->crypt_data;
+ }
+
+ mutex_exit(&fil_system->mutex);
+
+ return(crypt_data);
+}
+
/*******************************************************************//**
Increments the count of pending operation, if space is not being deleted.
@return TRUE if being deleted, and operation should be skipped */
@@ -7293,33 +7699,7 @@ fil_decr_pending_ops(
}
/******************************************************************
-Get crypt data for a tablespace */
-UNIV_INTERN
-fil_space_crypt_t*
-fil_space_get_crypt_data(
-/*=====================*/
- ulint id) /*!< in: space id */
-{
- fil_space_t* space;
- fil_space_crypt_t* crypt_data = NULL;
-
- ut_ad(fil_system);
-
- mutex_enter(&fil_system->mutex);
-
- space = fil_space_get_by_id(id);
-
- if (space != NULL) {
- crypt_data = space->crypt_data;
- }
-
- mutex_exit(&fil_system->mutex);
-
- return(crypt_data);
-}
-
-/******************************************************************
-Get crypt data for a tablespace */
+Set crypt data for a tablespace */
UNIV_INTERN
fil_space_crypt_t*
fil_space_set_crypt_data(
diff --git a/storage/innobase/fsp/fsp0file.cc b/storage/innobase/fsp/fsp0file.cc
index b3e85c58e42..501a8e58622 100644
--- a/storage/innobase/fsp/fsp0file.cc
+++ b/storage/innobase/fsp/fsp0file.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -33,8 +33,11 @@ Created 2013-7-26 by Kevin Lewis
#include "srv0start.h"
#include "ut0new.h"
#include "fil0crypt.h"
+#ifdef UNIV_HOTBACKUP
+#include "my_sys.h"
+#endif /* UNIV_HOTBACKUP */
-/** Initialize the name and flags of this datafile.
+/** Initialize the name, size and order of this datafile
@param[in] name tablespace name, will be copied
@param[in] flags tablespace flags */
void
@@ -47,6 +50,8 @@ Datafile::init(
m_name = mem_strdup(name);
m_flags = flags;
+ m_encryption_key = NULL;
+ m_encryption_iv = NULL;
}
/** Release the resources. */
@@ -60,10 +65,20 @@ Datafile::shutdown()
free_filepath();
+ if (m_encryption_key != NULL) {
+ ut_free(m_encryption_key);
+ m_encryption_key = NULL;
+ }
+
if (m_crypt_info) {
fil_space_destroy_crypt_data(&m_crypt_info);
}
+ if (m_encryption_iv != NULL) {
+ ut_free(m_encryption_iv);
+ m_encryption_iv = NULL;
+ }
+
free_first_page();
}
@@ -380,13 +395,15 @@ Datafile::free_first_page()
space ID and flags. The file should exist and be successfully opened
in order for this function to validate it.
@param[in] space_id The expected tablespace ID.
-@param[in] flags The expected tablespace flags.
+@param[in] flags The expected tablespace flags.
+@param[in] for_import if it is for importing
@retval DB_SUCCESS if tablespace is valid, DB_ERROR if not.
m_is_valid is also set true on success, else false. */
dberr_t
Datafile::validate_to_dd(
- ulint space_id,
- ulint flags)
+ ulint space_id,
+ ulint flags,
+ bool for_import)
{
dberr_t err;
@@ -397,7 +414,7 @@ Datafile::validate_to_dd(
/* Validate this single-table-tablespace with the data dictionary,
but do not compare the DATA_DIR flag, in case the tablespace was
remotely located. */
- err = validate_first_page();
+ err = validate_first_page(0, for_import);
if (err != DB_SUCCESS) {
return(err);
}
@@ -441,14 +458,52 @@ Datafile::validate_for_recovery()
ut_ad(is_open());
ut_ad(!srv_read_only_mode);
- err = validate_first_page();
+ err = validate_first_page(0, false);
switch (err) {
case DB_SUCCESS:
case DB_TABLESPACE_EXISTS:
+#ifdef UNIV_HOTBACKUP
+ err = restore_from_doublewrite(0);
+ if (err != DB_SUCCESS) {
+ return(err);
+ }
+ /* Free the previously read first page and then re-validate. */
+ free_first_page();
+ err = validate_first_page(0, false);
+ if (err == DB_SUCCESS) {
+ std::string filepath = fil_space_get_first_path(
+ m_space_id);
+ if (is_intermediate_file(filepath.c_str())) {
+ /* Existing intermediate file with same space
+ id is obsolete.*/
+ if (fil_space_free(m_space_id, FALSE)) {
+ err = DB_SUCCESS;
+ }
+ } else {
+ filepath.assign(m_filepath);
+ if (is_intermediate_file(filepath.c_str())) {
+ /* New intermediate file with same space id
+ shall be ignored.*/
+ err = DB_TABLESPACE_EXISTS;
+ /* Set all bits of 'flags' as a special
+ indicator for "ignore tablespace". Hopefully
+ InnoDB will never use all bits or at least all
+ bits set will not be a meaningful setting
+ otherwise.*/
+ m_flags = ~0;
+ }
+ }
+ }
+#endif /* UNIV_HOTBACKUP */
break;
default:
+ /* For encryption tablespace, we skip the retry step,
+ since it is only because the keyring is not ready. */
+ if (FSP_FLAGS_GET_ENCRYPTION(m_flags)) {
+ return(err);
+ }
/* Re-open the file in read-write mode Attempt to restore
page 0 from doublewrite and read the space ID from a survey
of the first few pages. */
@@ -476,7 +531,7 @@ Datafile::validate_for_recovery()
/* Free the previously read first page and then re-validate. */
free_first_page();
- err = validate_first_page();
+ err = validate_first_page(0, false);
}
if (err == DB_SUCCESS) {
@@ -491,12 +546,14 @@ tablespace is opened. This occurs before the fil_space_t is created
so the Space ID found here must not already be open.
m_is_valid is set true on success, else false.
@param[out] flush_lsn contents of FIL_PAGE_FILE_FLUSH_LSN
+@param[in] for_import if it is for importing
(only valid for the first file of the system tablespace)
@retval DB_SUCCESS on if the datafile is valid
@retval DB_CORRUPTION if the datafile is not readable
@retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */
dberr_t
-Datafile::validate_first_page(lsn_t* flush_lsn)
+Datafile::validate_first_page(lsn_t* flush_lsn,
+ bool for_import)
{
char* prev_name;
char* prev_filepath;
@@ -585,6 +642,51 @@ Datafile::validate_first_page(lsn_t* flush_lsn)
}
+#ifdef MYSQL_ENCRYPTION
+ /* For encrypted tablespace, check the encryption info in the
+ first page can be decrypt by master key, otherwise, this table
+ can't be open. And for importing, we skip checking it. */
+ if (FSP_FLAGS_GET_ENCRYPTION(m_flags) && !for_import) {
+ m_encryption_key = static_cast<byte*>(
+ ut_zalloc_nokey(ENCRYPTION_KEY_LEN));
+ m_encryption_iv = static_cast<byte*>(
+ ut_zalloc_nokey(ENCRYPTION_KEY_LEN));
+#ifdef UNIV_ENCRYPT_DEBUG
+ fprintf(stderr, "Got from file %lu:", m_space_id);
+#endif
+ if (!fsp_header_get_encryption_key(m_flags,
+ m_encryption_key,
+ m_encryption_iv,
+ m_first_page)) {
+ ib::error()
+ << "Encryption information in"
+ << " datafile: " << m_filepath
+ << " can't be decrypted"
+ << " , please confirm the keyfile"
+ << " is match and keyring plugin"
+ << " is loaded.";
+
+ m_is_valid = false;
+ free_first_page();
+ ut_free(m_encryption_key);
+ ut_free(m_encryption_iv);
+ m_encryption_key = NULL;
+ m_encryption_iv = NULL;
+ return(DB_CORRUPTION);
+ }
+
+ if (recv_recovery_is_on()
+ && memcmp(m_encryption_key,
+ m_encryption_iv,
+ ENCRYPTION_KEY_LEN) == 0) {
+ ut_free(m_encryption_key);
+ ut_free(m_encryption_iv);
+ m_encryption_key = NULL;
+ m_encryption_iv = NULL;
+ }
+ }
+#endif /* MYSQL_ENCRYPTION */
+
if (fil_space_read_name_and_filepath(
m_space_id, &prev_name, &prev_filepath)) {
@@ -988,13 +1090,11 @@ RemoteDatafile::create_link_file(
} else {
link_filepath = fil_make_filepath(NULL, name, ISL, false);
}
-
if (link_filepath == NULL) {
return(DB_ERROR);
}
prev_filepath = read_link_file(link_filepath);
-
if (prev_filepath) {
/* Truncate will call this with an existing
link file which contains the same filepath. */
@@ -1007,14 +1107,15 @@ RemoteDatafile::create_link_file(
}
/** Check if the file already exists. */
- FILE* file = NULL;
- bool exists;
- os_file_type_t ftype;
+ FILE* file = NULL;
+ bool exists;
+ os_file_type_t ftype;
success = os_file_status(link_filepath, &exists, &ftype);
ulint error = 0;
if (success && !exists) {
+
file = fopen(link_filepath, "w");
if (file == NULL) {
/* This call will print its own error message */
@@ -1025,6 +1126,7 @@ RemoteDatafile::create_link_file(
}
if (error != 0) {
+
ib::error() << "Cannot create file " << link_filepath << ".";
if (error == OS_FILE_ALREADY_EXISTS) {
@@ -1050,7 +1152,7 @@ RemoteDatafile::create_link_file(
error = os_file_get_last_error(true);
ib::error() <<
"Cannot write link file: "
- << filepath;
+ << link_filepath << " filepath: " << filepath;
err = DB_ERROR;
}
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index 109299a502b..9dc99f3f09d 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -31,30 +31,29 @@ Created 11/29/1995 Heikki Tuuri
#include "fsp0fsp.ic"
#endif
+#ifdef UNIV_HOTBACKUP
+# include "fut0lst.h"
+#else /* UNIV_HOTBACKUP */
#include "buf0buf.h"
#include "fil0fil.h"
#include "fil0crypt.h"
#include "mtr0log.h"
#include "ut0byte.h"
#include "page0page.h"
-#include "page0zip.h"
-#ifdef UNIV_HOTBACKUP
-# include "fut0lst.h"
-#else /* UNIV_HOTBACKUP */
-# include "fut0fut.h"
-# include "srv0srv.h"
-# include "srv0start.h"
-# include "ibuf0ibuf.h"
-# include "btr0btr.h"
-# include "btr0sea.h"
-# include "dict0boot.h"
-# include "log0log.h"
-#endif /* UNIV_HOTBACKUP */
-#include "dict0mem.h"
+#include "fut0fut.h"
+#include "srv0srv.h"
+#include "srv0start.h"
+#include "ibuf0ibuf.h"
+#include "btr0btr.h"
+#include "btr0sea.h"
+#include "dict0boot.h"
+#include "log0log.h"
#include "fsp0sysspace.h"
+#include "dict0mem.h"
#include "fsp0types.h"
-#ifndef UNIV_HOTBACKUP
+// JAN: MySQL 5.7 Encryption
+// #include <my_aes.h>
/** Returns an extent to the free list of a space.
@param[in] page_id page id in the extent
@@ -148,7 +147,7 @@ fseg_alloc_free_page_low(
, ibool has_done_reservation
#endif /* UNIV_DEBUG */
)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Gets a pointer to the space header and x-locks its page.
@param[in] id space id
@@ -205,6 +204,7 @@ fsp_flags_to_dict_tf(
bool page_compressed = FSP_FLAGS_GET_PAGE_COMPRESSION(fsp_flags);
ulint comp_level = FSP_FLAGS_GET_PAGE_COMPRESSION_LEVEL(fsp_flags);
bool atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(fsp_flags);
+
/* FSP_FLAGS_GET_TEMPORARY(fsp_flags) does not have an equivalent
flag position in the table flags. But it would go into flags2 if
any code is created where that is needed. */
@@ -215,6 +215,7 @@ fsp_flags_to_dict_tf(
return(flags);
}
+#endif /* !UNIV_HOTBACKUP */
/** Validate the tablespace flags.
These flags are stored in the tablespace header at offset FSP_SPACE_FLAGS.
@@ -234,11 +235,17 @@ fsp_flags_is_valid(
bool has_data_dir = FSP_FLAGS_HAS_DATA_DIR(flags);
bool is_shared = FSP_FLAGS_GET_SHARED(flags);
bool is_temp = FSP_FLAGS_GET_TEMPORARY(flags);
+ bool is_encryption = FSP_FLAGS_GET_ENCRYPTION(flags);
ulint unused = FSP_FLAGS_GET_UNUSED(flags);
bool page_compression = FSP_FLAGS_GET_PAGE_COMPRESSION(flags);
ulint page_compression_level = FSP_FLAGS_GET_PAGE_COMPRESSION_LEVEL(flags);
ulint atomic_writes = FSP_FLAGS_GET_ATOMIC_WRITES(flags);
+ const char *file;
+ ulint line;
+
+#define GOTO_ERROR file = __FILE__; line = __LINE__; goto err_exit;
+
DBUG_EXECUTE_IF("fsp_flags_is_valid_failure", return(false););
/* The Antelope row formats REDUNDANT and COMPACT did
@@ -254,60 +261,55 @@ fsp_flags_is_valid(
and externally stored parts. So if it is Post_antelope, it uses
Atomic BLOBs. */
if (post_antelope != atomic_blobs) {
- fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted atomic_blobs %d\n",
- flags, atomic_blobs);
+ GOTO_ERROR;
return(false);
}
/* Make sure there are no bits that we do not know about. */
if (unused != 0) {
- fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted unused %lu\n",
- flags, unused);
- return(false);
+ GOTO_ERROR;
}
/* The zip ssize can be zero if it is other than compressed row format,
or it could be from 1 to the max. */
if (zip_ssize > PAGE_ZIP_SSIZE_MAX) {
- fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted zip_ssize %lu max %d\n",
- flags, zip_ssize, PAGE_ZIP_SSIZE_MAX);
- return(false);
+ GOTO_ERROR;
}
/* The actual page size must be within 4k and 16K (3 =< ssize =< 5). */
if (page_ssize != 0
&& (page_ssize < UNIV_PAGE_SSIZE_MIN
|| page_ssize > UNIV_PAGE_SSIZE_MAX)) {
- fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted page_ssize %lu min:%lu:max:%lu\n",
- flags, page_ssize, UNIV_PAGE_SSIZE_MIN, UNIV_PAGE_SSIZE_MAX);
- return(false);
+ GOTO_ERROR;
}
/* Only single-table tablespaces use the DATA DIRECTORY clause.
It is not compatible with the TABLESPACE clause. Nor is it
compatible with the TEMPORARY clause. */
if (has_data_dir && (is_shared || is_temp)) {
- fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted has_data_dir %d is_shared %d is_temp %d\n",
- flags, has_data_dir, is_shared, is_temp);
+ GOTO_ERROR;
return(false);
}
+ /* Only single-table and not temp tablespaces use the encryption
+ clause. */
+ if (is_encryption && (is_shared || is_temp)) {
+ GOTO_ERROR;
+ }
+
/* Page compression level requires page compression and atomic blobs
to be set */
- if (page_compression_level || page_compression) {
+ if (page_compression_level || page_compression) {
if (!page_compression || !atomic_blobs) {
- fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted page_compression %d\n"
- "InnoDB: Error: page_compression_level %lu atomic_blobs %d\n",
- flags, page_compression, page_compression_level, atomic_blobs);
- return(false);
+ GOTO_ERROR;
}
}
if (atomic_writes > ATOMIC_WRITES_OFF) {
- fprintf(stderr, "InnoDB: Error: Tablespace flags %lu corrupted atomic_writes %lu\n",
- flags, atomic_writes);
+ GOTO_ERROR;
return (false);
}
+
#if UNIV_FORMAT_MAX != UNIV_FORMAT_B
# error UNIV_FORMAT_MAX != UNIV_FORMAT_B, Add more validations.
#endif
@@ -316,6 +318,24 @@ fsp_flags_is_valid(
#endif
return(true);
+
+err_exit:
+ ib::error() << "Tablespace flags: " << flags << " corrupted "
+ << " in file: " << file << " line: " << line
+ << " post_antelope: " << post_antelope
+ << " atomic_blobs: " << atomic_blobs
+ << " unused: " << unused
+ << " zip_ssize: " << zip_ssize << " max: " << PAGE_ZIP_SSIZE_MAX
+ << " page_ssize: " << page_ssize
+ << " " << UNIV_PAGE_SSIZE_MIN << ":" << UNIV_PAGE_SSIZE_MAX
+ << " has_data_dir: " << has_data_dir
+ << " is_shared: " << is_shared
+ << " is_temp: " << is_temp
+ << " is_encryption: " << is_encryption
+ << " page_compressed: " << page_compression
+ << " page_compression_level: " << page_compression_level
+ << " atomic_writes: " << atomic_writes;
+ return (false);
}
/** Check if tablespace is system temporary.
@@ -351,6 +371,7 @@ fsp_is_file_per_table(
&& !fsp_is_shared_tablespace(fsp_flags));
}
+#ifndef UNIV_HOTBACKUP
#ifdef UNIV_DEBUG
/** Skip some of the sanity checks that are time consuming even in debug mode
@@ -588,7 +609,7 @@ xdes_init(
the same as the tablespace header
@return pointer to the extent descriptor, NULL if the page does not
exist in the space or if the offset exceeds free limit */
-UNIV_INLINE MY_ATTRIBUTE((nonnull(1,4), warn_unused_result))
+UNIV_INLINE MY_ATTRIBUTE((warn_unused_result))
xdes_t*
xdes_get_descriptor_with_space_hdr(
fsp_header_t* sp_header,
@@ -883,6 +904,202 @@ fsp_header_init_fields(
}
#ifndef UNIV_HOTBACKUP
+/** Get the offset of encrytion information in page 0.
+@param[in] page_size page size.
+@return offset on success, otherwise 0. */
+static
+ulint
+fsp_header_get_encryption_offset(
+ const page_size_t& page_size)
+{
+ ulint offset;
+#ifdef UNIV_DEBUG
+ ulint left_size;
+#endif
+
+ offset = XDES_ARR_OFFSET + XDES_SIZE * xdes_arr_size(page_size);
+#ifdef UNIV_DEBUG
+ left_size = page_size.physical() - FSP_HEADER_OFFSET - offset
+ - FIL_PAGE_DATA_END;
+
+ ut_ad(left_size >= ENCRYPTION_INFO_SIZE_V2);
+#endif
+
+ return offset;
+}
+
+#if 0 /* MySQL 5.7 Encryption */
+/** Fill the encryption info.
+@param[in] space tablespace
+@param[in,out] encrypt_info buffer for encrypt key.
+@return true if success. */
+bool
+fsp_header_fill_encryption_info(
+ fil_space_t* space,
+ byte* encrypt_info)
+{
+ byte* ptr;
+ lint elen;
+ ulint master_key_id;
+ byte* master_key;
+ byte key_info[ENCRYPTION_KEY_LEN * 2];
+ ulint crc;
+ Encryption::Version version;
+#ifdef UNIV_ENCRYPT_DEBUG
+ const byte* data;
+ ulint i;
+#endif
+
+ /* Get master key from key ring */
+ Encryption::get_master_key(&master_key_id, &master_key, &version);
+ if (master_key == NULL) {
+ return(false);
+ }
+
+ memset(encrypt_info, 0, ENCRYPTION_INFO_SIZE_V2);
+ memset(key_info, 0, ENCRYPTION_KEY_LEN * 2);
+
+ /* Use the new master key to encrypt the tablespace
+ key. */
+ ut_ad(encrypt_info != NULL);
+ ptr = encrypt_info;
+
+ /* Write magic header. */
+ if (version == Encryption::ENCRYPTION_VERSION_1) {
+ memcpy(ptr, ENCRYPTION_KEY_MAGIC_V1, ENCRYPTION_MAGIC_SIZE);
+ } else {
+ memcpy(ptr, ENCRYPTION_KEY_MAGIC_V2, ENCRYPTION_MAGIC_SIZE);
+ }
+ ptr += ENCRYPTION_MAGIC_SIZE;
+
+ /* Write master key id. */
+ mach_write_to_4(ptr, master_key_id);
+ ptr += sizeof(ulint);
+
+ /* Write server uuid. */
+ if (version == Encryption::ENCRYPTION_VERSION_2) {
+ memcpy(ptr, Encryption::uuid, ENCRYPTION_SERVER_UUID_LEN);
+ ptr += ENCRYPTION_SERVER_UUID_LEN;
+ }
+
+ /* Write tablespace key to temp space. */
+ memcpy(key_info,
+ space->encryption_key,
+ ENCRYPTION_KEY_LEN);
+
+ /* Write tablespace iv to temp space. */
+ memcpy(key_info + ENCRYPTION_KEY_LEN,
+ space->encryption_iv,
+ ENCRYPTION_KEY_LEN);
+
+#ifdef UNIV_ENCRYPT_DEBUG
+ fprintf(stderr, "Set %lu:%lu ",space->id,
+ Encryption::master_key_id);
+ for (data = (const byte*) master_key, i = 0;
+ i < ENCRYPTION_KEY_LEN; i++)
+ fprintf(stderr, "%02lx", (ulong)*data++);
+ fprintf(stderr, " ");
+ for (data = (const byte*) space->encryption_key,
+ i = 0; i < ENCRYPTION_KEY_LEN; i++)
+ fprintf(stderr, "%02lx", (ulong)*data++);
+ fprintf(stderr, " ");
+ for (data = (const byte*) space->encryption_iv,
+ i = 0; i < ENCRYPTION_KEY_LEN; i++)
+ fprintf(stderr, "%02lx", (ulong)*data++);
+ fprintf(stderr, "\n");
+#endif
+ /* Encrypt tablespace key and iv. */
+ elen = my_aes_encrypt(
+ key_info,
+ ENCRYPTION_KEY_LEN * 2,
+ ptr,
+ master_key,
+ ENCRYPTION_KEY_LEN,
+ my_aes_256_ecb,
+ NULL, false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ my_free(master_key);
+ return(false);
+ }
+
+ ptr += ENCRYPTION_KEY_LEN * 2;
+
+ /* Write checksum bytes. */
+ crc = ut_crc32(key_info, ENCRYPTION_KEY_LEN * 2);
+ mach_write_to_4(ptr, crc);
+
+ my_free(master_key);
+ return(true);
+}
+#endif /* ! */
+
+/** Rotate the encryption info in the space header.
+@param[in] space tablespace
+@param[in] encrypt_info buffer for re-encrypt key.
+@param[in,out] mtr mini-transaction
+@return true if success. */
+bool
+fsp_header_rotate_encryption(
+ fil_space_t* space,
+ byte* encrypt_info,
+ mtr_t* mtr)
+{
+ buf_block_t* block;
+ ulint offset;
+
+ ut_ad(mtr);
+
+ const page_size_t page_size(space->flags);
+
+#if MYSQL_ENCRYPTION
+ page_t* page;
+ ulint master_key_id;
+ ut_ad(space->encryption_type != Encryption::NONE);
+ /* Fill encryption info. */
+ if (!fsp_header_fill_encryption_info(space,
+ encrypt_info)) {
+ return(false);
+ }
+#endif
+
+ /* Save the encryption info to the page 0. */
+ block = buf_page_get(page_id_t(space->id, 0),
+ page_size,
+ RW_SX_LATCH, mtr);
+ buf_block_dbg_add_level(block, SYNC_FSP_PAGE);
+ ut_ad(space->id == page_get_space_id(buf_block_get_frame(block)));
+
+ offset = fsp_header_get_encryption_offset(page_size);
+ ut_ad(offset != 0 && offset < UNIV_PAGE_SIZE);
+
+
+#if MYSQL_ENCRYPTION
+ page = buf_block_get_frame(block);
+ /* If is in recovering, skip all master key id is rotated
+ tablespaces. */
+ master_key_id = mach_read_from_4(
+ page + offset + ENCRYPTION_MAGIC_SIZE);
+ if (recv_recovery_is_on()
+ && master_key_id == Encryption::master_key_id) {
+ ut_ad(memcmp(page + offset,
+ ENCRYPTION_KEY_MAGIC_V1,
+ ENCRYPTION_MAGIC_SIZE) == 0
+ || memcmp(page + offset,
+ ENCRYPTION_KEY_MAGIC_V2,
+ ENCRYPTION_MAGIC_SIZE) == 0);
+ return(true);
+ }
+
+ mlog_write_string(page + offset,
+ encrypt_info,
+ ENCRYPTION_INFO_SIZE_V2,
+ mtr);
+#endif /* MYSQL_ENCRYPTION */
+
+ return(true);
+}
+
/** Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0.
@param[in] space_id space id
@@ -944,8 +1161,33 @@ fsp_header_init(
fsp_fill_free_list(!is_system_tablespace(space_id),
space, header, mtr);
+#if 0 /* MySQL 5.7 Encryption */
+ /* For encryption tablespace, we need to save the encryption
+ info to the page 0. */
+ if (FSP_FLAGS_GET_ENCRYPTION(space->flags)) {
+ ulint offset = fsp_header_get_encryption_offset(page_size);
+ byte encryption_info[ENCRYPTION_INFO_SIZE_V2];
+
+ if (offset == 0)
+ return(false);
+
+ if (!fsp_header_fill_encryption_info(space,
+ encryption_info)) {
+ space->encryption_type = Encryption::NONE;
+ memset(space->encryption_key, 0, ENCRYPTION_KEY_LEN);
+ memset(space->encryption_iv, 0, ENCRYPTION_KEY_LEN);
+ return(false);
+ }
+
+ mlog_write_string(page + offset,
+ encryption_info,
+ ENCRYPTION_INFO_SIZE_V2,
+ mtr);
+ }
+#endif /* ! */
+
if (space_id == srv_sys_space.space_id()) {
- if (btr_create(DICT_CLUSTERED | DICT_IBUF,
+ if (btr_create(DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF,
0, univ_page_size, DICT_IBUF_ID_MIN + space_id,
dict_ind_redundant, NULL, mtr) == FIL_NULL) {
return(false);
@@ -997,6 +1239,164 @@ fsp_header_get_page_size(
return(page_size_t(fsp_header_get_flags(page)));
}
+#if 0 /* MySQL 5.7 Encryption */
+/** Decoding the encryption info
+from the first page of a tablespace.
+@param[in/out] key key
+@param[in/out] iv iv
+@param[in] encryption_info encrytion info.
+@return true if success */
+bool
+fsp_header_decode_encryption_info(
+ byte* key,
+ byte* iv,
+ byte* encryption_info)
+{
+ byte* ptr;
+ ulint master_key_id;
+ byte* master_key = NULL;
+ lint elen;
+ byte key_info[ENCRYPTION_KEY_LEN * 2];
+ ulint crc1;
+ ulint crc2;
+ char srv_uuid[ENCRYPTION_SERVER_UUID_LEN + 1];
+ Encryption::Version version;
+#ifdef UNIV_ENCRYPT_DEBUG
+ const byte* data;
+ ulint i;
+#endif
+
+ ptr = encryption_info;
+
+ /* For compatibility with 5.7.11, we need to handle the
+ encryption information which created in this old version. */
+ if (memcmp(ptr, ENCRYPTION_KEY_MAGIC_V1,
+ ENCRYPTION_MAGIC_SIZE) == 0) {
+ version = Encryption::ENCRYPTION_VERSION_1;
+ } else {
+ version = Encryption::ENCRYPTION_VERSION_2;
+ }
+ /* Check magic. */
+ if (version == Encryption::ENCRYPTION_VERSION_2
+ && memcmp(ptr, ENCRYPTION_KEY_MAGIC_V2, ENCRYPTION_MAGIC_SIZE) != 0) {
+ /* We ignore report error for recovery,
+ since the encryption info maybe hasn't writen
+ into datafile when the table is newly created. */
+ if (!recv_recovery_is_on()) {
+ return(false);
+ } else {
+ return(true);
+ }
+ }
+ ptr += ENCRYPTION_MAGIC_SIZE;
+
+ /* Get master key id. */
+ master_key_id = mach_read_from_4(ptr);
+ ptr += sizeof(ulint);
+
+ /* Get server uuid. */
+ if (version == Encryption::ENCRYPTION_VERSION_2) {
+ memset(srv_uuid, 0, ENCRYPTION_SERVER_UUID_LEN + 1);
+ memcpy(srv_uuid, ptr, ENCRYPTION_SERVER_UUID_LEN);
+ ptr += ENCRYPTION_SERVER_UUID_LEN;
+ }
+
+ /* Get master key by key id. */
+ memset(key_info, 0, ENCRYPTION_KEY_LEN * 2);
+ if (version == Encryption::ENCRYPTION_VERSION_1) {
+ Encryption::get_master_key(master_key_id, NULL, &master_key);
+ } else {
+ Encryption::get_master_key(master_key_id, srv_uuid, &master_key);
+ }
+ if (master_key == NULL) {
+ return(false);
+ }
+
+#ifdef UNIV_ENCRYPT_DEBUG
+ fprintf(stderr, "%lu ", master_key_id);
+ for (data = (const byte*) master_key, i = 0;
+ i < ENCRYPTION_KEY_LEN; i++)
+ fprintf(stderr, "%02lx", (ulong)*data++);
+#endif
+
+ /* Decrypt tablespace key and iv. */
+ elen = my_aes_decrypt(
+ ptr,
+ ENCRYPTION_KEY_LEN * 2,
+ key_info,
+ master_key,
+ ENCRYPTION_KEY_LEN,
+ my_aes_256_ecb, NULL, false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ my_free(master_key);
+ return(NULL);
+ }
+
+ /* Check checksum bytes. */
+ ptr += ENCRYPTION_KEY_LEN * 2;
+
+ crc1 = mach_read_from_4(ptr);
+ crc2 = ut_crc32(key_info, ENCRYPTION_KEY_LEN * 2);
+ if (crc1 != crc2) {
+ ib::error() << "Failed to decrpt encryption information,"
+ << " please check key file is not changed!";
+ return(false);
+ }
+
+ /* Get tablespace key */
+ memcpy(key, key_info, ENCRYPTION_KEY_LEN);
+
+ /* Get tablespace iv */
+ memcpy(iv, key_info + ENCRYPTION_KEY_LEN,
+ ENCRYPTION_KEY_LEN);
+
+#ifdef UNIV_ENCRYPT_DEBUG
+ fprintf(stderr, " ");
+ for (data = (const byte*) key,
+ i = 0; i < ENCRYPTION_KEY_LEN; i++)
+ fprintf(stderr, "%02lx", (ulong)*data++);
+ fprintf(stderr, " ");
+ for (data = (const byte*) iv,
+ i = 0; i < ENCRYPTION_KEY_LEN; i++)
+ fprintf(stderr, "%02lx", (ulong)*data++);
+ fprintf(stderr, "\n");
+#endif
+
+ my_free(master_key);
+
+ if (Encryption::master_key_id < master_key_id) {
+ Encryption::master_key_id = master_key_id;
+ memcpy(Encryption::uuid, srv_uuid, ENCRYPTION_SERVER_UUID_LEN);
+ }
+
+ return(true);
+}
+
+/** Reads the encryption key from the first page of a tablespace.
+@param[in] fsp_flags tablespace flags
+@param[in/out] key tablespace key
+@param[in/out] iv tablespace iv
+@param[in] page first page of a tablespace
+@return true if success */
+bool
+fsp_header_get_encryption_key(
+ ulint fsp_flags,
+ byte* key,
+ byte* iv,
+ page_t* page)
+{
+ ulint offset;
+ const page_size_t page_size(fsp_flags);
+ offset = fsp_header_get_encryption_offset(page_size);
+ if (offset == 0) {
+ return(false);
+ }
+
+ return(fsp_header_decode_encryption_info(key, iv, page + offset));
+}
+#endif /* ! */
+
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
Increases the space size field of a space. */
@@ -1065,7 +1465,7 @@ data file.
@param[in,out] header tablespace header
@param[in,out] mtr mini-transaction
@return true if success */
-static UNIV_COLD __attribute__((warn_unused_result))
+static UNIV_COLD MY_ATTRIBUTE((warn_unused_result))
bool
fsp_try_extend_data_file_with_pages(
fil_space_t* space,
@@ -1097,6 +1497,7 @@ fsp_try_extend_data_file_with_pages(
@param[in,out] header tablespace header
@param[in,out] mtr mini-transaction
@return whether the tablespace was extended */
+static UNIV_COLD MY_ATTRIBUTE((nonnull))
ulint
fsp_try_extend_data_file(
fil_space_t* space,
@@ -1577,7 +1978,7 @@ initialized (may be the same as mtr)
@retval block rw_lock_x_lock_count(&block->lock) == 1 if allocation succeeded
(init_mtr == mtr, or the page was not previously freed in mtr)
@retval block (not allocated or initialized) otherwise */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
buf_block_t*
fsp_alloc_free_page(
ulint space,
@@ -1971,7 +2372,6 @@ fsp_alloc_seg_inode(
&& !fsp_alloc_seg_inode_page(space_header, mtr)) {
return(NULL);
}
-
const page_size_t page_size(
mach_read_from_4(FSP_SPACE_FLAGS + space_header));
@@ -2926,24 +3326,27 @@ fseg_alloc_free_page_general(
return(block);
}
-/** Check that we have at least 2 frag pages free in the first extent of a
-single-table tablespace, and they are also physically initialized to the data
-file. That is we have already extended the data file so that those pages are
-inside the data file. If not, this function extends the tablespace with
-pages.
+/** Check that we have at least n_pages frag pages free in the first extent
+of a single-table tablespace, and they are also physically initialized to
+the data file. That is we have already extended the data file so that those
+pages are inside the data file. If not, this function extends the tablespace
+with pages.
@param[in,out] space tablespace
@param[in,out] space_header tablespace header, x-latched
@param[in] size size of the tablespace in pages,
-must be less than FSP_EXTENT_SIZE/2
+must be less than FSP_EXTENT_SIZE
@param[in,out] mtr mini-transaction
-@return true if there were at least 3 free pages, or we were able to extend */
+@param[in] n_pages number of pages to reserve
+@return true if there were at least n_pages free pages, or we were able
+to extend */
static
bool
fsp_reserve_free_pages(
fil_space_t* space,
fsp_header_t* space_header,
ulint size,
- mtr_t* mtr)
+ mtr_t* mtr,
+ ulint n_pages)
{
xdes_t* descr;
ulint n_used;
@@ -2957,13 +3360,12 @@ fsp_reserve_free_pages(
ut_a(n_used <= size);
- return(size >= n_used + 2
+ return(size >= n_used + n_pages
|| fsp_try_extend_data_file_with_pages(
- space, n_used + 1, space_header, mtr));
+ space, n_used + n_pages - 1, space_header, mtr));
}
-/**********************************************************************//**
-Reserves free pages from a tablespace. All mini-transactions which may
+/** Reserves free pages from a tablespace. All mini-transactions which may
use several pages from the tablespace should call this function beforehand
and reserve enough free extents so that they certainly will be able
to do their operation, like a B-tree page split, fully. Reservations
@@ -2982,23 +3384,33 @@ The purpose is to avoid dead end where the database is full but the
user cannot free any space because these freeing operations temporarily
reserve some space.
-Single-table tablespaces whose size is < 32 pages are a special case. In this
-function we would liberally reserve several 64 page extents for every page
-split or merge in a B-tree. But we do not want to waste disk space if the table
-only occupies < 32 pages. That is why we apply different rules in that special
-case, just ensuring that there are 3 free pages available.
-@return TRUE if we were able to make the reservation */
+Single-table tablespaces whose size is < FSP_EXTENT_SIZE pages are a special
+case. In this function we would liberally reserve several extents for
+every page split or merge in a B-tree. But we do not want to waste disk space
+if the table only occupies < FSP_EXTENT_SIZE pages. That is why we apply
+different rules in that special case, just ensuring that there are n_pages
+free pages available.
+
+@param[out] n_reserved number of extents actually reserved; if we
+ return true and the tablespace size is <
+ FSP_EXTENT_SIZE pages, then this can be 0,
+ otherwise it is n_ext
+@param[in] space_id tablespace identifier
+@param[in] n_ext number of extents to reserve
+@param[in] alloc_type page reservation type (FSP_BLOB, etc)
+@param[in,out] mtr the mini transaction
+@param[in] n_pages for small tablespaces (tablespace size is
+ less than FSP_EXTENT_SIZE), number of free
+ pages to reserve.
+@return true if we were able to make the reservation */
bool
fsp_reserve_free_extents(
-/*=====================*/
- ulint* n_reserved,/*!< out: number of extents actually reserved; if we
- return TRUE and the tablespace size is < 64 pages,
- then this can be 0, otherwise it is n_ext */
- ulint space_id,/*!< in: space id */
- ulint n_ext, /*!< in: number of extents to reserve */
+ ulint* n_reserved,
+ ulint space_id,
+ ulint n_ext,
fsp_reserve_t alloc_type,
- /*!< in: page reservation type */
- mtr_t* mtr) /*!< in/out: mini-transaction */
+ mtr_t* mtr,
+ ulint n_pages)
{
fsp_header_t* space_header;
ulint n_free_list_ext;
@@ -3009,7 +3421,7 @@ fsp_reserve_free_extents(
ulint reserve= 0;
size_t total_reserved = 0;
ulint rounds = 0;
- ulint n_pages_added;
+ ulint n_pages_added = 0;
ut_ad(mtr);
*n_reserved = n_ext;
@@ -3022,10 +3434,11 @@ try_again:
size = mach_read_from_4(space_header + FSP_SIZE);
ut_ad(size == space->size_in_header);
- if (alloc_type != FSP_BLOB && size < FSP_EXTENT_SIZE) {
+ if (size < FSP_EXTENT_SIZE && n_pages < FSP_EXTENT_SIZE / 2) {
/* Use different rules for small single-table tablespaces */
*n_reserved = 0;
- return(fsp_reserve_free_pages(space, space_header, size, mtr));
+ return(fsp_reserve_free_pages(space, space_header, size,
+ mtr, n_pages));
}
n_free_list_ext = flst_get_len(space_header + FSP_FREE);
@@ -3105,7 +3518,6 @@ try_to_extend:
<< " rounds: " << rounds
<< " total_reserved: " << total_reserved << ".";
}
-
goto try_again;
}
@@ -3420,33 +3832,8 @@ fseg_page_is_free(
}
/**********************************************************************//**
-Checks if a single page is free.
-@return true if free */
-UNIV_INTERN
-bool
-fsp_page_is_free_func(
-/*==============*/
- ulint space_id, /*!< in: space id */
- ulint page_no, /*!< in: page offset */
- mtr_t* mtr, /*!< in/out: mini-transaction */
- const char *file,
- ulint line)
-{
- ut_ad(mtr);
-
- const fil_space_t* space = mtr_x_lock_space(space_id, mtr);
- const page_size_t page_size(space->flags);
-
- xdes_t* descr = xdes_get_descriptor(space_id, page_no, page_size, mtr);
- ut_a(descr);
-
- return xdes_mtr_get_bit(
- descr, XDES_FREE_BIT, page_no % FSP_EXTENT_SIZE, mtr);
-}
-
-/**********************************************************************//**
Frees an extent of a segment to the space free list. */
-static __attribute__((nonnull))
+static MY_ATTRIBUTE((nonnull))
void
fseg_free_extent(
/*=============*/
@@ -3929,7 +4316,6 @@ fseg_header::to_stream(std::ostream& out) const
{
const ulint space = mtr_read_ulint(m_header + FSEG_HDR_SPACE,
MLOG_4BYTES, m_mtr);
-
const ulint page_no = mtr_read_ulint(m_header + FSEG_HDR_PAGE_NO,
MLOG_4BYTES, m_mtr);
@@ -3944,6 +4330,31 @@ fseg_header::to_stream(std::ostream& out) const
#endif /* UNIV_DEBUG */
/**********************************************************************//**
+Checks if a single page is free.
+@return true if free */
+UNIV_INTERN
+bool
+fsp_page_is_free_func(
+/*==============*/
+ ulint space_id, /*!< in: space id */
+ ulint page_no, /*!< in: page offset */
+ mtr_t* mtr, /*!< in/out: mini-transaction */
+ const char *file,
+ ulint line)
+{
+ ut_ad(mtr);
+
+ const fil_space_t* space = mtr_x_lock_space(space_id, mtr);
+ const page_size_t page_size(space->flags);
+
+ xdes_t* descr = xdes_get_descriptor(space_id, page_no, page_size, mtr);
+ ut_a(descr);
+
+ return xdes_mtr_get_bit(
+ descr, XDES_FREE_BIT, page_no % FSP_EXTENT_SIZE, mtr);
+}
+
+/**********************************************************************//**
Compute offset after xdes where crypt data can be stored
@return offset */
ulint
diff --git a/storage/innobase/fsp/fsp0space.cc b/storage/innobase/fsp/fsp0space.cc
index 6f1ef8ceb9d..f66f7b8fc78 100644
--- a/storage/innobase/fsp/fsp0space.cc
+++ b/storage/innobase/fsp/fsp0space.cc
@@ -27,8 +27,10 @@ Created 2012-11-16 by Sunny Bains as srv/srv0space.cc
#include "fsp0space.h"
#include "fsp0sysspace.h"
+#ifndef UNIV_HOTBACKUP
#include "fsp0fsp.h"
#include "os0file.h"
+#endif /* !UNIV_HOTBACKUP */
#include "my_sys.h"
@@ -70,34 +72,6 @@ Tablespace::shutdown()
m_space_id = ULINT_UNDEFINED;
}
-/** Get the sum of the file sizes of each Datafile in a tablespace
-@return ULINT_UNDEFINED if the size is invalid else the sum of sizes */
-ulint
-Tablespace::get_sum_of_sizes() const
-{
- ulint sum = 0;
-
- files_t::const_iterator end = m_files.end();
-
- for (files_t::const_iterator it = m_files.begin(); it != end; ++it) {
-
-#ifndef _WIN32
- if (sizeof(off_t) < 5
- && it->m_size >= (1UL << (32UL - UNIV_PAGE_SIZE_SHIFT))) {
-
- ib::error() << "File size must be < 4 GB with this"
- " MySQL binary-operating system combination."
- " In some OS's < 2 GB";
-
- return(ULINT_UNDEFINED);
- }
-#endif /* _WIN32 */
- sum += it->m_size;
- }
-
- return(sum);
-}
-
/** Note that the data file was found.
@param[in,out] file Data file object to set */
void
diff --git a/storage/innobase/fsp/fsp0sysspace.cc b/storage/innobase/fsp/fsp0sysspace.cc
index b1d3ab92c7e..66b5da15e8b 100644
--- a/storage/innobase/fsp/fsp0sysspace.cc
+++ b/storage/innobase/fsp/fsp0sysspace.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -357,8 +357,14 @@ SysTablespace::check_size(
os_offset_t size = os_file_get_size(file.m_handle);
ut_a(size != (os_offset_t) -1);
- /* Round size downward to megabytes */
- ulint rounded_size_pages = (ulint) (size >> UNIV_PAGE_SIZE_SHIFT);
+ /* Under some error conditions like disk full scenarios
+ or file size reaching filesystem limit the data file
+ could contain an incomplete extent at the end. When we
+ extend a data file and if some failure happens, then
+ also the data file could contain an incomplete extent.
+ So we need to round the size downward to a megabyte.*/
+
+ ulint rounded_size_pages = get_pages_from_size(size);
/* If last file */
if (&file == &m_files.back() && m_auto_extend_last_file) {
@@ -531,6 +537,7 @@ SysTablespace::open_file(
return(err);
}
+#ifndef UNIV_HOTBACKUP
/** Check the tablespace header for this tablespace.
@param[out] flushed_lsn the value of FIL_PAGE_FILE_FLUSH_LSN
@return DB_SUCCESS or error code */
@@ -574,7 +581,7 @@ SysTablespace::read_lsn_and_check_flags(lsn_t* flushed_lsn)
first datafile. */
for (int retry = 0; retry < 2; ++retry) {
- err = it->validate_first_page(flushed_lsn);
+ err = it->validate_first_page(flushed_lsn, false);
if (err != DB_SUCCESS
&& (retry == 1
@@ -605,7 +612,7 @@ SysTablespace::read_lsn_and_check_flags(lsn_t* flushed_lsn)
return(DB_SUCCESS);
}
-
+#endif /* !UNIV_HOTBACKUP */
/** Check if a file can be opened in the correct mode.
@param[in] file data file object
@param[out] reason exact reason if file_status check failed.
@@ -752,7 +759,7 @@ SysTablespace::file_found(
/* Need to create the system tablespace for new raw device. */
return(file.m_type == SRV_NEW_RAW);
}
-
+#ifndef UNIV_HOTBACKUP
/** Check the data file specification.
@param[out] create_new_db true if a new database is to be created
@param[in] min_expected_size Minimum expected tablespace size in bytes
@@ -772,11 +779,7 @@ SysTablespace::check_file_spec(
return(DB_ERROR);
}
- ulint tablespace_size = get_sum_of_sizes();
- if (tablespace_size == ULINT_UNDEFINED) {
- return(DB_ERROR);
- } else if (tablespace_size
- < min_expected_size / UNIV_PAGE_SIZE) {
+ if (get_sum_of_sizes() < min_expected_size / UNIV_PAGE_SIZE) {
ib::error() << "Tablespace size must be at least "
<< min_expected_size / (1024 * 1024) << " MB";
@@ -987,7 +990,7 @@ SysTablespace::open_or_create(
return(err);
}
-
+#endif /* UNIV_HOTBACKUP */
/** Normalize the file size, convert from megabytes to number of pages. */
void
SysTablespace::normalize()
diff --git a/storage/innobase/fts/fts0ast.cc b/storage/innobase/fts/fts0ast.cc
index 14e52a99e18..8c542aab289 100644
--- a/storage/innobase/fts/fts0ast.cc
+++ b/storage/innobase/fts/fts0ast.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2007, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -161,7 +161,7 @@ fts_ast_create_node_term_for_parser(
/* '%' as first char is forbidden for LIKE in internal SQL parser;
'%' as last char is reserved for wildcard search;*/
- if (len == 0 || len > fts_max_token_size
+ if (len == 0 || len > FTS_MAX_WORD_LEN
|| ptr[0] == '%' || ptr[len - 1] == '%') {
return(NULL);
}
@@ -537,6 +537,36 @@ fts_ast_node_print(
fts_ast_node_print_recursive(node, 0);
}
+/** Check only union operation involved in the node
+@param[in] node ast node to check
+@return true if the node contains only union else false. */
+bool
+fts_ast_node_check_union(
+ fts_ast_node_t* node)
+{
+ if (node->type == FTS_AST_LIST
+ || node->type == FTS_AST_SUBEXP_LIST
+ || node->type == FTS_AST_PARSER_PHRASE_LIST) {
+
+ for (node = node->list.head; node; node = node->next) {
+ if (!fts_ast_node_check_union(node)) {
+ return(false);
+ }
+ }
+
+ } else if (node->type == FTS_AST_OPER
+ && (node->oper == FTS_IGNORE
+ || node->oper == FTS_EXIST)) {
+
+ return(false);
+ } else if (node->type == FTS_AST_TEXT) {
+ /* Distance or phrase search query. */
+ return(false);
+ }
+
+ return(true);
+}
+
/******************************************************************//**
Traverse the AST - in-order traversal, except for the FTX_EXIST and FTS_IGNORE
nodes, which will be ignored in the first pass of each level, and visited in a
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 5edee71a13a..5faa68be0ea 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -208,19 +208,20 @@ struct fts_tokenize_param_t {
ulint add_pos; /*!< Added position for tokens */
};
-/****************************************************************//**
-Run SYNC on the table, i.e., write out data from the cache to the
+/** Run SYNC on the table, i.e., write out data from the cache to the
FTS auxiliary INDEX table and clear the cache at the end.
@param[in,out] sync sync state
@param[in] unlock_cache whether unlock cache lock when write node
@param[in] wait whether wait when a sync is in progress
+@param[in] has_dict whether has dict operation lock
@return DB_SUCCESS if all OK */
static
dberr_t
fts_sync(
fts_sync_t* sync,
bool unlock_cache,
- bool wait);
+ bool wait,
+ bool has_dict);
/****************************************************************//**
Release all resources help by the words rb tree e.g., the node ilist. */
@@ -1979,7 +1980,6 @@ fts_create_common_tables(
func_exit:
if (error != DB_SUCCESS) {
-
for (it = common_tables.begin(); it != common_tables.end();
++it) {
row_drop_table_for_mysql(
@@ -3648,7 +3648,7 @@ fts_add_doc_by_id(
DBUG_EXECUTE_IF(
"fts_instrument_sync_debug",
- fts_sync(cache->sync, true, true);
+ fts_sync(cache->sync, true, true, false);
);
DEBUG_SYNC_C("fts_instrument_sync_request");
@@ -3929,6 +3929,8 @@ fts_write_node(
doc_id_t first_doc_id;
char table_name[MAX_FULL_NAME_LEN];
+ ut_a(node->ilist != NULL);
+
if (*graph) {
info = (*graph)->info;
} else {
@@ -4446,7 +4448,7 @@ fts_sync_index(
ut_ad(rbt_validate(index_cache->words));
- error = fts_sync_write_words(sync->trx, index_cache, sync->unlock_cache);
+ error = fts_sync_write_words(trx, index_cache, sync->unlock_cache);
#ifdef FTS_DOC_STATS_DEBUG
/* FTS_RESOLVE: the word counter info in auxiliary table "DOC_ID"
@@ -4463,13 +4465,11 @@ fts_sync_index(
}
/** Check if index cache has been synced completely
-@param[in,out] sync sync state
@param[in,out] index_cache index cache
@return true if index is synced, otherwise false. */
static
bool
fts_sync_index_check(
- fts_sync_t* sync,
fts_index_cache_t* index_cache)
{
const ib_rbt_node_t* rbt_node;
@@ -4492,14 +4492,36 @@ fts_sync_index_check(
return(true);
}
-/*********************************************************************//**
-Commit the SYNC, change state of processed doc ids etc.
+/** Reset synced flag in index cache when rollback
+@param[in,out] index_cache index cache */
+static
+void
+fts_sync_index_reset(
+ fts_index_cache_t* index_cache)
+{
+ const ib_rbt_node_t* rbt_node;
+
+ for (rbt_node = rbt_first(index_cache->words);
+ rbt_node != NULL;
+ rbt_node = rbt_next(index_cache->words, rbt_node)) {
+
+ fts_tokenizer_word_t* word;
+ word = rbt_value(fts_tokenizer_word_t, rbt_node);
+
+ fts_node_t* fts_node;
+ fts_node = static_cast<fts_node_t*>(ib_vector_last(word->nodes));
+
+ fts_node->synced = false;
+ }
+}
+
+/** Commit the SYNC, change state of processed doc ids etc.
+@param[in,out] sync sync state
@return DB_SUCCESS if all OK */
static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
fts_sync_commit(
-/*============*/
- fts_sync_t* sync) /*!< in: sync state */
+ fts_sync_t* sync)
{
dberr_t error;
trx_t* trx = sync->trx;
@@ -4550,6 +4572,8 @@ fts_sync_commit(
<< " ins/sec";
}
+ /* Avoid assertion in trx_free(). */
+ trx->dict_operation_lock_mode = 0;
trx_free_for_background(trx);
return(error);
@@ -4572,6 +4596,10 @@ fts_sync_rollback(
index_cache = static_cast<fts_index_cache_t*>(
ib_vector_get(cache->indexes, i));
+ /* Reset synced flag so nodes will not be skipped
+ in the next sync, see fts_sync_write_words(). */
+ fts_sync_index_reset(index_cache);
+
for (j = 0; fts_index_selector[j].value; ++j) {
if (index_cache->ins_graph[j] != NULL) {
@@ -4597,6 +4625,9 @@ fts_sync_rollback(
rw_lock_x_unlock(&cache->lock);
fts_sql_rollback(trx);
+
+ /* Avoid assertion in trx_free(). */
+ trx->dict_operation_lock_mode = 0;
trx_free_for_background(trx);
}
@@ -4605,13 +4636,15 @@ FTS auxiliary INDEX table and clear the cache at the end.
@param[in,out] sync sync state
@param[in] unlock_cache whether unlock cache lock when write node
@param[in] wait whether wait when a sync is in progress
+@param[in] has_dict whether has dict operation lock
@return DB_SUCCESS if all OK */
static
dberr_t
fts_sync(
fts_sync_t* sync,
bool unlock_cache,
- bool wait)
+ bool wait,
+ bool has_dict)
{
ulint i;
dberr_t error = DB_SUCCESS;
@@ -4640,6 +4673,12 @@ fts_sync(
DEBUG_SYNC_C("fts_sync_begin");
fts_sync_begin(sync);
+ /* When sync in background, we hold dict operation lock
+ to prevent DDL like DROP INDEX, etc. */
+ if (has_dict) {
+ sync->trx->dict_operation_lock_mode = RW_S_LATCH;
+ }
+
begin_sync:
if (cache->total_size > fts_max_cache_size) {
/* Avoid the case: sync never finish when
@@ -4676,7 +4715,7 @@ begin_sync:
ib_vector_get(cache->indexes, i));
if (index_cache->index->to_be_dropped
- || fts_sync_index_check(sync, index_cache)) {
+ || fts_sync_index_check(index_cache)) {
continue;
}
@@ -4691,6 +4730,7 @@ end_sync:
}
rw_lock_x_lock(&cache->lock);
+ sync->interrupted = false;
sync->in_progress = false;
os_event_set(sync->event);
rw_lock_x_unlock(&cache->lock);
@@ -4714,19 +4754,23 @@ FTS auxiliary INDEX table and clear the cache at the end.
@param[in,out] table fts table
@param[in] unlock_cache whether unlock cache when write node
@param[in] wait whether wait for existing sync to finish
+@param[in] has_dict whether has dict operation lock
@return DB_SUCCESS on success, error code on failure. */
dberr_t
fts_sync_table(
dict_table_t* table,
bool unlock_cache,
- bool wait)
+ bool wait,
+ bool has_dict)
{
dberr_t err = DB_SUCCESS;
ut_ad(table->fts);
- if (!dict_table_is_discarded(table) && table->fts->cache) {
- err = fts_sync(table->fts->cache->sync, unlock_cache, wait);
+ if (!dict_table_is_discarded(table) && table->fts->cache
+ && !dict_table_is_corrupted(table)) {
+ err = fts_sync(table->fts->cache->sync,
+ unlock_cache, wait, has_dict);
}
return(err);
@@ -5114,7 +5158,7 @@ fts_tokenize_document(
ut_a(doc->charset);
doc->tokens = rbt_create_arg_cmp(
- sizeof(fts_token_t), innobase_fts_text_cmp, (void*) doc->charset);
+ sizeof(fts_token_t), innobase_fts_text_cmp, (void*) doc->charset);
if (parser != NULL) {
fts_tokenize_param_t fts_param;
@@ -5809,6 +5853,8 @@ fts_update_doc_id(
if (error == DB_SUCCESS) {
dict_index_t* clust_index;
+ dict_col_t* col = dict_table_get_nth_col(
+ table, table->fts->doc_col);
ufield->exp = NULL;
@@ -5816,8 +5862,8 @@ fts_update_doc_id(
clust_index = dict_table_get_first_index(table);
- ufield->field_no = dict_col_get_clust_pos(
- &table->cols[table->fts->doc_col], clust_index);
+ ufield->field_no = dict_col_get_clust_pos(col, clust_index);
+ dict_col_copy_type(col, dfield_get_type(&ufield->new_val));
/* It is possible we update record that has
not yet be sync-ed from last crash. */
@@ -6784,11 +6830,7 @@ fts_fake_hex_to_dec(
#ifdef UNIV_DEBUG
ret =
#endif /* UNIV_DEBUG */
-#ifdef _WIN32
- sscanf(tmp_id, "%016llu", &dec_id);
-#else
- sscanf(tmp_id, "%016llu", &dec_id);
-#endif /* _WIN32 */
+ sscanf(tmp_id, "%016" UINT64scan, &dec_id);
ut_ad(ret == 1);
return dec_id;
@@ -7995,10 +8037,9 @@ func_exit:
consistent state. For now consistency is check only by ensuring
index->page_no != FIL_NULL
@param[out] base_table table has host fts index
-@param[in,out] trx trx handler
-@return true if check certifies auxillary tables are sane false otherwise. */
-bool
-fts_is_corrupt(
+@param[in,out] trx trx handler */
+void
+fts_check_corrupt(
dict_table_t* base_table,
trx_t* trx)
{
@@ -8016,7 +8057,7 @@ fts_is_corrupt(
fts_get_table_name(&fts_table, table_name);
dict_table_t* aux_table = dict_table_open_on_name(
- table_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
+ table_name, true, FALSE, DICT_ERR_IGNORE_NONE);
if (aux_table == NULL) {
dict_set_corrupted(
@@ -8045,6 +8086,4 @@ fts_is_corrupt(
dict_table_close(aux_table, FALSE, FALSE);
}
-
- return(sane);
}
diff --git a/storage/innobase/fts/fts0opt.cc b/storage/innobase/fts/fts0opt.cc
index 89cdcf26591..5989aff83f4 100644
--- a/storage/innobase/fts/fts0opt.cc
+++ b/storage/innobase/fts/fts0opt.cc
@@ -602,7 +602,7 @@ fts_zip_read_word(
/* Finished decompressing block. */
if (zip->zp->avail_in == 0) {
- /* Free the block that's been decompressed. */
+ /* Free the block thats been decompressed. */
if (zip->pos > 0) {
ulint prev = zip->pos - 1;
@@ -1507,6 +1507,12 @@ fts_optimize_write_word(
fts_node_t* node = (fts_node_t*) ib_vector_get(nodes, i);
if (error == DB_SUCCESS) {
+ /* Skip empty node. */
+ if (node->ilist == NULL) {
+ ut_ad(node->ilist_size == 0);
+ continue;
+ }
+
error = fts_write_node(
trx, &graph, fts_table, word, node);
@@ -2635,7 +2641,6 @@ fts_optimize_remove_table(
/** Send sync fts cache for the table.
@param[in] table table to sync */
-UNIV_INTERN
void
fts_optimize_request_sync_table(
dict_table_t* table)
@@ -2650,7 +2655,7 @@ fts_optimize_request_sync_table(
/* FTS optimizer thread is already exited */
if (fts_opt_start_shutdown) {
- ib::info() << "Try to remove table " << table->name
+ ib::info() << "Try to sync table " << table->name
<< " after FTS optimize thread exiting.";
return;
}
@@ -2964,7 +2969,7 @@ fts_optimize_sync_table(
if (table) {
if (dict_table_has_fts_index(table) && table->fts->cache) {
- fts_sync_table(table, true, false);
+ fts_sync_table(table, true, false, true);
}
dict_table_close(table, FALSE, FALSE);
@@ -3122,26 +3127,7 @@ fts_optimize_thread(
ib_vector_get(tables, i));
if (slot->state != FTS_STATE_EMPTY) {
- dict_table_t* table = NULL;
-
- /*slot->table may be freed, so we try to open
- table by slot->table_id.*/
- table = dict_table_open_on_id(
- slot->table_id, FALSE,
- DICT_TABLE_OP_NORMAL);
-
- if (table) {
-
- if (dict_table_has_fts_index(table)) {
- fts_sync_table(table, false, true);
- }
-
- if (table->fts) {
- fts_free(table);
- }
-
- dict_table_close(table, FALSE, FALSE);
- }
+ fts_optimize_sync_table(slot->table_id);
}
}
}
@@ -3155,7 +3141,7 @@ fts_optimize_thread(
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -3189,11 +3175,9 @@ fts_optimize_is_init(void)
return(fts_optimize_wq != NULL);
}
-/**********************************************************************//**
-Signal the optimize thread to prepare for shutdown. */
+/** Shutdown fts optimize thread. */
void
-fts_optimize_start_shutdown(void)
-/*=============================*/
+fts_optimize_shutdown()
{
ut_ad(!srv_read_only_mode);
@@ -3222,17 +3206,5 @@ fts_optimize_start_shutdown(void)
os_event_destroy(fts_opt_shutdown_event);
ib_wqueue_free(fts_optimize_wq);
-}
-
-/**********************************************************************//**
-Reset the work queue. */
-void
-fts_optimize_end(void)
-/*==================*/
-{
- ut_ad(!srv_read_only_mode);
-
- // FIXME: Potential race condition here: We should wait for
- // the optimize thread to confirm shutdown.
fts_optimize_wq = NULL;
}
diff --git a/storage/innobase/fts/fts0que.cc b/storage/innobase/fts/fts0que.cc
index 8abeb63f0a4..dee7c59a58b 100644
--- a/storage/innobase/fts/fts0que.cc
+++ b/storage/innobase/fts/fts0que.cc
@@ -153,6 +153,13 @@ struct fts_query_t {
bool multi_exist; /*!< multiple FTS_EXIST oper */
st_mysql_ftparser* parser; /*!< fts plugin parser */
+
+ /** limit value for the fts query */
+ ulonglong limit;
+
+ /** number of docs fetched by query. This is to restrict the
+ result with limit value */
+ ulonglong n_docs;
};
/** For phrase matching, first we collect the documents and the positions
@@ -2700,7 +2707,7 @@ fts_query_phrase_split(
/*****************************************************************//**
Text/Phrase search.
@return DB_SUCCESS or error code */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
fts_query_phrase_search(
/*====================*/
@@ -3209,6 +3216,11 @@ fts_query_filter_doc_ids(
ulint decoded = 0;
ib_rbt_t* doc_freqs = word_freq->doc_freqs;
+ if (query->limit != ULONG_UNDEFINED
+ && query->n_docs >= query->limit) {
+ return(DB_SUCCESS);
+ }
+
/* Decode the ilist and add the doc ids to the query doc_id set. */
while (decoded < len) {
ulint freq = 0;
@@ -3296,11 +3308,17 @@ fts_query_filter_doc_ids(
/* Add the word to the document's matched RB tree. */
fts_query_add_word_to_document(query, doc_id, word);
}
+
+ if (query->limit != ULONG_UNDEFINED
+ && query->limit <= ++query->n_docs) {
+ goto func_exit;
+ }
}
/* Some sanity checks. */
ut_a(doc_id == node->last_doc_id);
+func_exit:
if (query->total_size > fts_result_cache_limit) {
return(DB_FTS_EXCEED_RESULT_CACHE_LIMIT);
} else {
@@ -3904,19 +3922,24 @@ fts_query_can_optimize(
}
}
-/*******************************************************************//**
-FTS Query entry point.
+/** FTS Query entry point.
+@param[in] trx transaction
+@param[in] index fts index to search
+@param[in] flags FTS search mode
+@param[in] query_str FTS query
+@param[in] query_len FTS query string len in bytes
+@param[in,out] result result doc ids
+@param[in] limit limit value
@return DB_SUCCESS if successful otherwise error code */
dberr_t
fts_query(
-/*======*/
- trx_t* trx, /*!< in: transaction */
- dict_index_t* index, /*!< in: The FTS index to search */
- uint flags, /*!< in: FTS search mode */
- const byte* query_str, /*!< in: FTS query */
- ulint query_len, /*!< in: FTS query string len
- in bytes */
- fts_result_t** result) /*!< in/out: result doc ids */
+ trx_t* trx,
+ dict_index_t* index,
+ uint flags,
+ const byte* query_str,
+ ulint query_len,
+ fts_result_t** result,
+ ulonglong limit)
{
fts_query_t query;
dberr_t error = DB_SUCCESS;
@@ -3971,13 +3994,16 @@ fts_query(
if (flags & FTS_EXPAND) {
query.wildcard_words = rbt_create_arg_cmp(
- sizeof(fts_string_t), innobase_fts_text_cmp, (void*)charset);
+ sizeof(fts_string_t), innobase_fts_text_cmp, (void *)charset);
}
query.total_size += SIZEOF_RBT_CREATE;
query.total_docs = dict_table_get_n_rows(index->table);
+ query.limit = limit;
+
+ query.n_docs = 0;
#ifdef FTS_DOC_STATS_DEBUG
if (ft_enable_diag_print) {
error = fts_get_total_word_count(
@@ -4053,6 +4079,19 @@ fts_query(
fts_result_cache_limit = 2048;
);
+ /* Optimisation is allowed for limit value
+ when
+ i) No ranking involved
+ ii) Only FTS Union operations involved. */
+ if (query.limit != ULONG_UNDEFINED
+ && !fts_ast_node_check_union(ast)) {
+ query.limit = ULONG_UNDEFINED;
+ }
+
+ DBUG_EXECUTE_IF("fts_union_limit_off",
+ query.limit = ULONG_UNDEFINED;
+ );
+
/* Traverse the Abstract Syntax Tree (AST) and execute
the query. */
query.error = fts_ast_visit(
diff --git a/storage/innobase/gis/gis0rtree.cc b/storage/innobase/gis/gis0rtree.cc
index 45f0bd97821..512fce3ff47 100644
--- a/storage/innobase/gis/gis0rtree.cc
+++ b/storage/innobase/gis/gis0rtree.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -152,7 +152,9 @@ rtr_index_build_node_ptr(
tuple = dtuple_create(heap, n_unique + 1);
- dtuple_set_n_fields_cmp(tuple, n_unique);
+ /* For rtree internal node, we need to compare page number
+ fields. */
+ dtuple_set_n_fields_cmp(tuple, n_unique + 1);
dict_index_copy_types(tuple, index, n_unique);
@@ -621,7 +623,7 @@ update_mbr:
/**************************************************************//**
Update parent page's MBR and Predicate lock information during a split */
-static __attribute__((nonnull))
+static MY_ATTRIBUTE((nonnull))
void
rtr_adjust_upper_level(
/*===================*/
@@ -723,8 +725,6 @@ rtr_adjust_upper_level(
node_ptr_upper, &rec, &dummy_big_rec, 0, NULL, mtr);
if (err == DB_FAIL) {
- ut_ad(!cursor.rtr_info);
-
cursor.rtr_info = sea_cur->rtr_info;
cursor.tree_height = sea_cur->tree_height;
@@ -1025,6 +1025,7 @@ rtr_page_split_and_insert(
lock_prdt_t new_prdt;
rec_t* first_rec = NULL;
int first_rec_group = 1;
+ ulint n_iterations = 0;
if (!*heap) {
*heap = mem_heap_create(1024);
@@ -1229,6 +1230,15 @@ func_start:
page_cur_search(insert_block, cursor->index, tuple,
PAGE_CUR_LE, page_cursor);
+ /* It's possible that the new record is too big to be inserted into
+ the page, and it'll need the second round split in this case.
+ We test this scenario here*/
+ DBUG_EXECUTE_IF("rtr_page_need_second_split",
+ if (n_iterations == 0) {
+ rec = NULL;
+ goto after_insert; }
+ );
+
rec = page_cur_tuple_insert(page_cursor, tuple, cursor->index,
offsets, heap, n_ext, mtr);
@@ -1247,6 +1257,9 @@ func_start:
again. */
}
+#ifdef UNIV_DEBUG
+after_insert:
+#endif
/* Calculate the mbr on the upper half-page, and the mbr on
original page. */
rtr_page_cal_mbr(cursor->index, block, &mbr, *heap);
@@ -1279,6 +1292,7 @@ func_start:
block, new_block, mtr);
}
+
/* If the new res insert fail, we need to do another split
again. */
if (!rec) {
@@ -1289,9 +1303,12 @@ func_start:
ibuf_reset_free_bits(block);
}
- *offsets = rtr_page_get_father_block(
- NULL, *heap, cursor->index, block, mtr,
- NULL, cursor);
+ /* We need to clean the parent path here and search father
+ node later, otherwise, it's possible that find a wrong
+ parent. */
+ rtr_clean_rtr_info(cursor->rtr_info, true);
+ cursor->rtr_info = NULL;
+ n_iterations++;
rec_t* i_rec = page_rec_get_next(page_get_infimum_rec(
buf_block_get_frame(block)));
@@ -1411,19 +1428,19 @@ rtr_page_copy_rec_list_end_no_locks(
page_cur_t page_cur;
page_cur_t cur1;
rec_t* cur_rec;
- dtuple_t* tuple;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- ulint n_fields = 0;
+ ulint offsets_1[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets1 = offsets_1;
+ ulint offsets_2[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets2 = offsets_2;
ulint moved = 0;
bool is_leaf = page_is_leaf(new_page);
- rec_offs_init(offsets_);
+ rec_offs_init(offsets_1);
+ rec_offs_init(offsets_2);
page_cur_position(rec, block, &cur1);
if (page_cur_is_before_first(&cur1)) {
-
page_cur_move_to_next(&cur1);
}
@@ -1436,30 +1453,27 @@ rtr_page_copy_rec_list_end_no_locks(
page_get_infimum_rec(buf_block_get_frame(new_block)));
page_cur_position(cur_rec, new_block, &page_cur);
- n_fields = dict_index_get_n_fields(index);
-
/* Copy records from the original page to the new page */
while (!page_cur_is_after_last(&cur1)) {
rec_t* cur1_rec = page_cur_get_rec(&cur1);
rec_t* ins_rec;
- /* Find the place to insert. */
- tuple = dict_index_build_data_tuple(index, cur1_rec,
- n_fields, heap);
-
if (page_rec_is_infimum(cur_rec)) {
cur_rec = page_rec_get_next(cur_rec);
}
+ offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+ ULINT_UNDEFINED, &heap);
while (!page_rec_is_supremum(cur_rec)) {
ulint cur_matched_fields = 0;
int cmp;
- offsets = rec_get_offsets(
- cur_rec, index, offsets,
- dtuple_get_n_fields_cmp(tuple), &heap);
- cmp = cmp_dtuple_rec_with_match(tuple, cur_rec, offsets,
- &cur_matched_fields);
+ offsets2 = rec_get_offsets(cur_rec, index, offsets2,
+ ULINT_UNDEFINED, &heap);
+ cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
+ offsets1, offsets2,
+ index, FALSE,
+ &cur_matched_fields);
if (cmp < 0) {
page_cur_move_to_prev(&page_cur);
break;
@@ -1490,11 +1504,11 @@ rtr_page_copy_rec_list_end_no_locks(
cur_rec = page_cur_get_rec(&page_cur);
- offsets = rec_get_offsets(cur1_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
+ offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+ ULINT_UNDEFINED, &heap);
ins_rec = page_cur_insert_rec_low(cur_rec, index,
- cur1_rec, offsets, mtr);
+ cur1_rec, offsets1, mtr);
if (UNIV_UNLIKELY(!ins_rec)) {
fprintf(stderr, "page number %ld and %ld\n",
(long)new_block->page.id.page_no(),
@@ -1540,17 +1554,16 @@ rtr_page_copy_rec_list_start_no_locks(
{
page_cur_t cur1;
rec_t* cur_rec;
- dtuple_t* tuple;
- ulint offsets_[REC_OFFS_NORMAL_SIZE];
- ulint* offsets = offsets_;
- ulint n_fields = 0;
+ ulint offsets_1[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets1 = offsets_1;
+ ulint offsets_2[REC_OFFS_NORMAL_SIZE];
+ ulint* offsets2 = offsets_2;
page_cur_t page_cur;
ulint moved = 0;
bool is_leaf = page_is_leaf(buf_block_get_frame(block));
- rec_offs_init(offsets_);
-
- n_fields = dict_index_get_n_fields(index);
+ rec_offs_init(offsets_1);
+ rec_offs_init(offsets_2);
page_cur_set_before_first(block, &cur1);
page_cur_move_to_next(&cur1);
@@ -1563,23 +1576,23 @@ rtr_page_copy_rec_list_start_no_locks(
rec_t* cur1_rec = page_cur_get_rec(&cur1);
rec_t* ins_rec;
- /* Find the place to insert. */
- tuple = dict_index_build_data_tuple(index, cur1_rec,
- n_fields, heap);
-
if (page_rec_is_infimum(cur_rec)) {
cur_rec = page_rec_get_next(cur_rec);
}
+ offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+ ULINT_UNDEFINED, &heap);
+
while (!page_rec_is_supremum(cur_rec)) {
ulint cur_matched_fields = 0;
int cmp;
- offsets = rec_get_offsets(cur_rec, index, offsets,
- dtuple_get_n_fields_cmp(tuple),
- &heap);
- cmp = cmp_dtuple_rec_with_match(tuple, cur_rec, offsets,
- &cur_matched_fields);
+ offsets2 = rec_get_offsets(cur_rec, index, offsets2,
+ ULINT_UNDEFINED, &heap);
+ cmp = cmp_rec_rec_with_match(cur1_rec, cur_rec,
+ offsets1, offsets2,
+ index, FALSE,
+ &cur_matched_fields);
if (cmp < 0) {
page_cur_move_to_prev(&page_cur);
cur_rec = page_cur_get_rec(&page_cur);
@@ -1612,11 +1625,11 @@ rtr_page_copy_rec_list_start_no_locks(
cur_rec = page_cur_get_rec(&page_cur);
- offsets = rec_get_offsets(cur1_rec, index, offsets,
- ULINT_UNDEFINED, &heap);
+ offsets1 = rec_get_offsets(cur1_rec, index, offsets1,
+ ULINT_UNDEFINED, &heap);
ins_rec = page_cur_insert_rec_low(cur_rec, index,
- cur1_rec, offsets, mtr);
+ cur1_rec, offsets1, mtr);
if (UNIV_UNLIKELY(!ins_rec)) {
fprintf(stderr, "page number %ld and %ld\n",
(long)new_block->page.id.page_no(),
@@ -1689,36 +1702,6 @@ rtr_merge_mbr_changed(
mbr++;
}
- if (!changed) {
- rec_t* rec1;
- rec_t* rec2;
- ulint* offsets1;
- ulint* offsets2;
- mem_heap_t* heap;
-
- heap = mem_heap_create(100);
-
- rec1 = page_rec_get_next(
- page_get_infimum_rec(
- buf_block_get_frame(merge_block)));
-
- offsets1 = rec_get_offsets(
- rec1, index, NULL, ULINT_UNDEFINED, &heap);
-
- rec2 = page_rec_get_next(
- page_get_infimum_rec(
- buf_block_get_frame(block)));
- offsets2 = rec_get_offsets(
- rec2, index, NULL, ULINT_UNDEFINED, &heap);
-
- /* Check any primary key fields have been changed */
- if (cmp_rec_rec(rec1, rec2, offsets1, offsets2, index) != 0) {
- changed = true;
- }
-
- mem_heap_free(heap);
- }
-
return(changed);
}
@@ -1887,7 +1870,7 @@ rtr_estimate_n_rows_in_range(
/* Read mbr from tuple. */
const dfield_t* dtuple_field;
- ulint dtuple_f_len __attribute__((unused));
+ ulint dtuple_f_len MY_ATTRIBUTE((unused));
rtr_mbr_t range_mbr;
double range_area;
byte* range_mbr_ptr;
diff --git a/storage/innobase/gis/gis0sea.cc b/storage/innobase/gis/gis0sea.cc
index 26440b5fa96..2c0c5b453a3 100644
--- a/storage/innobase/gis/gis0sea.cc
+++ b/storage/innobase/gis/gis0sea.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -310,7 +310,7 @@ rtr_pcur_getnext_from_path(
page_cursor->rec = NULL;
if (mode == PAGE_CUR_RTREE_LOCATE) {
- if (level == target_level) {
+ if (level == target_level && level == 0) {
ulint low_match;
found = false;
@@ -336,10 +336,15 @@ rtr_pcur_getnext_from_path(
}
}
} else {
+ page_cur_mode_t page_mode = mode;
+
+ if (level == target_level
+ && target_level != 0) {
+ page_mode = PAGE_CUR_RTREE_GET_FATHER;
+ }
found = rtr_cur_search_with_match(
- block, index, tuple,
- PAGE_CUR_RTREE_LOCATE, page_cursor,
- btr_cur->rtr_info);
+ block, index, tuple, page_mode,
+ page_cursor, btr_cur->rtr_info);
/* Save the position of parent if needed */
if (found && need_parent) {
@@ -428,6 +433,9 @@ rtr_pcur_getnext_from_path(
page_cur_get_block(page_cursor),
r_cur);
+ btr_cur->low_match = level != 0 ?
+ DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1
+ : btr_cur->low_match;
break;
}
@@ -641,6 +649,41 @@ rtr_pcur_open_low(
}
}
+/* Get the rtree page father.
+@param[in] index rtree index
+@param[in] block child page in the index
+@param[in] mtr mtr
+@param[in] sea_cur search cursor, contains information
+ about parent nodes in search
+@param[in] cursor cursor on node pointer record,
+ its page x-latched */
+void
+rtr_page_get_father(
+ dict_index_t* index,
+ buf_block_t* block,
+ mtr_t* mtr,
+ btr_cur_t* sea_cur,
+ btr_cur_t* cursor)
+{
+ mem_heap_t* heap = mem_heap_create(100);
+#ifdef UNIV_DEBUG
+ ulint* offsets;
+
+ offsets = rtr_page_get_father_block(
+ NULL, heap, index, block, mtr, sea_cur, cursor);
+
+ ulint page_no = btr_node_ptr_get_child_page_no(cursor->page_cur.rec,
+ offsets);
+
+ ut_ad(page_no == block->page.id.page_no());
+#else
+ rtr_page_get_father_block(
+ NULL, heap, index, block, mtr, sea_cur, cursor);
+#endif
+
+ mem_heap_free(heap);
+}
+
/************************************************************//**
Returns the father block to a page. It is assumed that mtr holds
an X or SX latch on the tree.
@@ -658,6 +701,7 @@ rtr_page_get_father_block(
btr_cur_t* cursor) /*!< out: cursor on node pointer record,
its page x-latched */
{
+
rec_t* rec = page_rec_get_next(
page_get_infimum_rec(buf_block_get_frame(block)));
btr_cur_position(index, rec, block, cursor);
@@ -785,14 +829,13 @@ rtr_get_father_node(
ulint n_fields;
bool new_rtr = false;
-get_parent:
/* Try to optimally locate the parent node. Level should always
less than sea_cur->tree_height unless the root is splitting */
if (sea_cur && sea_cur->tree_height > level) {
ut_ad(mtr_memo_contains_flagged(mtr,
dict_index_get_lock(index),
- MTR_MEMO_X_LOCK
+ MTR_MEMO_X_LOCK
| MTR_MEMO_SX_LOCK));
ret = rtr_cur_restore_position(
BTR_CONT_MODIFY_TREE, sea_cur, level, mtr);
@@ -812,6 +855,8 @@ get_parent:
page_cur_position(rec,
btr_pcur_get_block(r_cursor),
btr_cur_get_page_cur(btr_cur));
+ btr_cur->rtr_info = sea_cur->rtr_info;
+ btr_cur->tree_height = sea_cur->tree_height;
ut_ad(rtr_compare_cursor_rec(
index, btr_cur, page_no, &heap));
goto func_exit;
@@ -838,14 +883,13 @@ get_parent:
BTR_CONT_MODIFY_TREE, btr_cur, 0,
__FILE__, __LINE__, mtr);
-
} else {
/* btr_validate */
ut_ad(level >= 1);
ut_ad(!sea_cur);
btr_cur_search_to_nth_level(
- index, level - 1, tuple, PAGE_CUR_RTREE_LOCATE,
+ index, level, tuple, PAGE_CUR_RTREE_LOCATE,
BTR_CONT_MODIFY_TREE, btr_cur, 0,
__FILE__, __LINE__, mtr);
@@ -856,50 +900,11 @@ get_parent:
|| (btr_cur->low_match != n_fields)) {
ret = rtr_pcur_getnext_from_path(
tuple, PAGE_CUR_RTREE_LOCATE, btr_cur,
- level - 1, BTR_CONT_MODIFY_TREE,
+ level, BTR_CONT_MODIFY_TREE,
true, mtr);
ut_ad(ret && btr_cur->low_match == n_fields);
}
-
- /* Since there could be some identical recs in different
- pages, we still need to compare the page_no field to
- verify we have the right parent. */
- btr_pcur_t* r_cursor = rtr_get_parent_cursor(btr_cur,
- level,
- false);
- rec = btr_pcur_get_rec(r_cursor);
-
- ulint* offsets = rec_get_offsets(rec, index, NULL,
- ULINT_UNDEFINED, &heap);
- while (page_no != btr_node_ptr_get_child_page_no(rec, offsets)) {
- ret = rtr_pcur_getnext_from_path(
- tuple, PAGE_CUR_RTREE_LOCATE, btr_cur,
- level - 1, BTR_CONT_MODIFY_TREE,
- true, mtr);
-
- ut_ad(ret && btr_cur->low_match == n_fields);
-
- /* There must be a rec in the path, if the path
- is run out, the spatial index is corrupted. */
- if (!ret) {
- mutex_enter(&dict_sys->mutex);
- dict_set_corrupted_index_cache_only(index);
- mutex_exit(&dict_sys->mutex);
-
- ib::info() << "InnoDB: Corruption of a"
- " spatial index " << index->name
- << " of table " << index->table->name;
- break;
- }
- r_cursor = rtr_get_parent_cursor(btr_cur, level, false);
- rec = btr_pcur_get_rec(r_cursor);
- offsets = rec_get_offsets(rec, index, NULL,
- ULINT_UNDEFINED, &heap);
- }
-
- sea_cur = btr_cur;
- goto get_parent;
}
ret = rtr_compare_cursor_rec(
@@ -1249,8 +1254,8 @@ rtr_check_discard_page(
mutex_exit(&index->rtr_track->rtr_active_mutex);
lock_mutex_enter();
- lock_prdt_free_from_discard_page(block, lock_sys->prdt_hash);
- lock_prdt_free_from_discard_page(block, lock_sys->prdt_page_hash);
+ lock_prdt_page_free_from_discard(block, lock_sys->prdt_hash);
+ lock_prdt_page_free_from_discard(block, lock_sys->prdt_page_hash);
lock_mutex_exit();
}
@@ -1784,6 +1789,10 @@ rtr_cur_search_with_match(
}
}
break;
+ case PAGE_CUR_RTREE_GET_FATHER:
+ cmp = cmp_dtuple_rec_with_gis_internal(
+ tuple, rec, offsets);
+ break;
default:
/* WITHIN etc. */
cmp = cmp_dtuple_rec_with_gis(
@@ -1807,6 +1816,12 @@ rtr_cur_search_with_match(
if (!is_leaf) {
ulint page_no;
node_seq_t new_seq;
+ bool is_loc;
+
+ is_loc = (orig_mode
+ == PAGE_CUR_RTREE_LOCATE
+ || orig_mode
+ == PAGE_CUR_RTREE_GET_FATHER);
offsets = rec_get_offsets(
rec, index, offsets,
@@ -1827,8 +1842,7 @@ rtr_cur_search_with_match(
new_seq, level - 1, 0,
NULL, 0);
- if (orig_mode
- == PAGE_CUR_RTREE_LOCATE) {
+ if (is_loc) {
rtr_non_leaf_insert_stack_push(
index,
rtr_info->parent_path,
@@ -1838,8 +1852,7 @@ rtr_cur_search_with_match(
if (!srv_read_only_mode
&& (rtr_info->need_page_lock
- || orig_mode
- != PAGE_CUR_RTREE_LOCATE)) {
+ || !is_loc)) {
/* Lock the page, preventing it
from being shrunk */
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index e12cc313019..9615e7f5386 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -50,6 +50,8 @@ this program; if not, write to the Free Software Foundation, Inc.,
#include <sql_show.h>
#include <sql_table.h>
#include <sql_tablespace.h>
+// MySQL 5.7 Header */
+// #include <sql_thd_internal_api.h>
#include <table_cache.h>
#include <my_check_opt.h>
#include <my_bitmap.h>
@@ -123,8 +125,10 @@ this program; if not, write to the Free Software Foundation, Inc.,
#define thd_get_trx_isolation(X) ((enum_tx_isolation)thd_tx_isolation(X))
+extern "C" void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
+
#ifdef MYSQL_DYNAMIC_PLUGIN
-#define tc_size 2000
+#define tc_size 400
#define tdc_size 400
#endif
@@ -137,14 +141,13 @@ this program; if not, write to the Free Software Foundation, Inc.,
/* for ha_innopart, Native InnoDB Partitioning. */
/* JAN: TODO: MySQL 5.7 Native InnoDB Partitioning */
-//#include "ha_innopart.h"
+#ifdef HAVE_HA_INNOPART_H
+#include "ha_innopart.h"
+#endif
+
#include <mysql/plugin.h>
#include <mysql/service_wsrep.h>
-# ifndef MYSQL_PLUGIN_IMPORT
-# define MYSQL_PLUGIN_IMPORT /* nothing */
-# endif /* MYSQL_PLUGIN_IMPORT */
-
#ifdef WITH_WSREP
#include "dict0priv.h"
#include "../storage/innobase/include/ut0byte.h"
@@ -172,27 +175,6 @@ static int innobase_wsrep_set_checkpoint(handlerton* hton, const XID* xid);
static int innobase_wsrep_get_checkpoint(handlerton* hton, XID* xid);
#endif /* WITH_WSREP */
-static
-void
-innobase_set_cursor_view(
-/*=====================*/
- handlerton* hton, /*!< in: innobase hton */
- THD* thd, /*!< in: user thread handle */
- void* curview);/*!< in: Consistent cursor view to be set */
-static
-void*
-innobase_create_cursor_view(
-/*========================*/
- handlerton* hton, /*!< in: innobase hton */
- THD* thd); /*!< in: user thread handle */
-static
-void
-innobase_close_cursor_view(
-/*=======================*/
- handlerton* hton, /*!< in: innobase hton */
- THD* thd, /*!< in: user thread handle */
- void* curview);/*!< in: Consistent read view to be closed */
-
/** to protect innobase_open_files */
static mysql_mutex_t innobase_share_mutex;
/** to force correct commit order in binlog */
@@ -213,7 +195,7 @@ static const long AUTOINC_NEW_STYLE_LOCKING = 1;
static const long AUTOINC_NO_LOCKING = 2;
static long innobase_log_buffer_size;
-static long innobase_open_files;
+static long innobase_open_files=0;
static long innobase_autoinc_lock_mode;
static ulong innobase_commit_concurrency = 0;
static ulong innobase_read_io_threads;
@@ -292,7 +274,8 @@ enum default_row_format_enum {
DEFAULT_ROW_FORMAT_COMPACT = 1,
DEFAULT_ROW_FORMAT_DYNAMIC = 2,
};
-/* JAN: TODO: MySQL 5.7 */
+
+static
void set_my_errno(int err)
{
errno = err;
@@ -492,6 +475,7 @@ static PSI_mutex_info all_innodb_mutexes[] = {
PSI_KEY(ibuf_mutex),
PSI_KEY(ibuf_pessimistic_insert_mutex),
PSI_KEY(log_sys_mutex),
+ PSI_KEY(log_sys_write_mutex),
PSI_KEY(mutex_list_mutex),
PSI_KEY(page_zip_stat_per_index_mutex),
PSI_KEY(purge_sys_pq_mutex),
@@ -529,6 +513,7 @@ static PSI_mutex_info all_innodb_mutexes[] = {
PSI_KEY(rtr_ssn_mutex),
PSI_KEY(trx_sys_mutex),
PSI_KEY(zip_pad_mutex),
+ PSI_KEY(master_key_id_mutex),
};
# endif /* UNIV_PFS_MUTEX */
@@ -554,10 +539,7 @@ static PSI_rwlock_info all_innodb_rwlocks[] = {
PSI_RWLOCK_KEY(index_tree_rw_lock),
PSI_RWLOCK_KEY(index_online_log),
PSI_RWLOCK_KEY(dict_table_stats),
- PSI_RWLOCK_KEY(hash_table_locks),
-# ifdef UNIV_DEBUG
- PSI_RWLOCK_KEY(buf_chunk_map_latch)
-# endif /* UNIV_DEBUG */
+ PSI_RWLOCK_KEY(hash_table_locks)
};
# endif /* UNIV_PFS_RWLOCK */
@@ -580,6 +562,7 @@ static PSI_thread_info all_innodb_threads[] = {
PSI_KEY(srv_master_thread),
PSI_KEY(srv_monitor_thread),
PSI_KEY(srv_purge_thread),
+ PSI_KEY(srv_worker_thread),
PSI_KEY(trx_rollback_clean_thread),
};
# endif /* UNIV_PFS_THREAD */
@@ -645,70 +628,42 @@ ib_cb_t innodb_api_cb[] = {
(ib_cb_t) ib_cfg_bk_commit_interval,
(ib_cb_t) ib_ut_strerr,
(ib_cb_t) ib_cursor_stmt_begin,
- (ib_cb_t) ib_trx_read_only
+ (ib_cb_t) ib_trx_read_only,
+ (ib_cb_t) ib_is_virtual_table
};
-/**
- Test a file path whether it is same as mysql data directory path.
-
- @param path null terminated character string
-
- @return
- @retval TRUE The path is different from mysql data directory.
- @retval FALSE The path is same as mysql data directory.
-*/
-static bool is_mysql_datadir_path(const char *path)
+/******************************************************************//**
+Function used to loop a thread (for debugging/instrumentation
+purpose). */
+void
+srv_debug_loop(void)
+/*================*/
{
- if (path == NULL)
- return false;
-
- char mysql_data_dir[FN_REFLEN], path_dir[FN_REFLEN];
- convert_dirname(path_dir, path, NullS);
- convert_dirname(mysql_data_dir, mysql_unpacked_real_data_home, NullS);
- size_t mysql_data_home_len= dirname_length(mysql_data_dir);
- size_t path_len = dirname_length(path_dir);
-
- if (path_len < mysql_data_home_len)
- return true;
-
- if (!lower_case_file_system)
- return(memcmp(mysql_data_dir, path_dir, mysql_data_home_len));
-
- return(files_charset_info->coll->strnncoll(files_charset_info,
- (uchar *) path_dir, path_len,
- (uchar *) mysql_data_dir,
- mysql_data_home_len,
- TRUE));
+ ibool set = TRUE;
+ while (set) {
+ os_thread_yield();
+ }
}
+/******************************************************************//**
+Debug function used to read a MBR data */
-static int mysql_tmpfile_path(const char *path, const char *prefix)
+#ifdef UNIV_DEBUG
+void
+srv_mbr_debug(const byte* data)
{
- DBUG_ASSERT(path != NULL);
- DBUG_ASSERT((strlen(path) + strlen(prefix)) <= FN_REFLEN);
-
- char filename[FN_REFLEN];
- File fd = create_temp_file(filename, path, prefix,
-#ifdef __WIN__
- O_BINARY | O_TRUNC | O_SEQUENTIAL |
- O_SHORT_LIVED |
-#endif /* __WIN__ */
- O_CREAT | O_EXCL | O_RDWR | O_TEMPORARY,
- MYF(MY_WME));
- if (fd >= 0) {
-#ifndef __WIN__
- /*
- This can be removed once the following bug is fixed:
- Bug #28903 create_temp_file() doesn't honor O_TEMPORARY option
- (file not removed) (Unix)
- */
- unlink(filename);
-#endif /* !__WIN__ */
- }
-
- return fd;
+ double a, b, c , d;
+ a = mach_double_read(data);
+ data += sizeof(double);
+ b = mach_double_read(data);
+ data += sizeof(double);
+ c = mach_double_read(data);
+ data += sizeof(double);
+ d = mach_double_read(data);
+ ut_ad(a && b && c &&d);
}
+#endif
static void innodb_remember_check_sysvar_funcs();
mysql_var_check_func check_sysvar_enum;
@@ -744,37 +699,6 @@ ha_create_table_option innodb_table_option_list[]=
HA_TOPTION_END
};
-/******************************************************************//**
-Function used to loop a thread (for debugging/instrumentation
-purpose). */
-void
-srv_debug_loop(void)
-/*================*/
-{
- ibool set = TRUE;
-
- while (set) {
- os_thread_yield();
- }
-}
-
-/******************************************************************//**
-Debug function used to read a MBR data */
-#ifdef UNIV_DEBUG
-void
-srv_mbr_debug(const byte* data)
-{
- double a, b, c , d;
- a = mach_double_read(data);
- data += sizeof(double);
- b = mach_double_read(data);
- data += sizeof(double);
- c = mach_double_read(data);
- data += sizeof(double);
- d = mach_double_read(data);
- ut_ad(a && b && c &&d);
-}
-#endif
/*************************************************************//**
Check whether valid argument given to innodb_ft_*_stopword_table.
This function is registered as a callback with MySQL.
@@ -790,6 +714,8 @@ innodb_stopword_table_validate(
for update function */
struct st_mysql_value* value); /*!< in: incoming string */
+static bool is_mysql_datadir_path(const char *path);
+
/** Validate passed-in "value" is a valid directory name.
This function is registered as a callback with MySQL.
@param[in,out] thd thread handle
@@ -840,6 +766,7 @@ innodb_tmpdir_validate(
return(1);
}
+ os_normalize_path(alter_tmp_dir);
my_realpath(tmp_abs_path, alter_tmp_dir, 0);
size_t tmp_abs_len = strlen(tmp_abs_path);
@@ -910,6 +837,7 @@ uint
get_field_offset(
const TABLE* table,
const Field* field);
+
/*************************************************************//**
Check for a valid value of innobase_compression_algorithm.
@return 0 for valid innodb_compression_algorithm. */
@@ -943,9 +871,41 @@ innodb_encrypt_tables_validate(
static const char innobase_hton_name[]= "InnoDB";
+static const char* deprecated_innodb_support_xa
+ = "Using innodb_support_xa is deprecated and the"
+ " parameter may be removed in future releases.";
+
+static const char* deprecated_innodb_support_xa_off
+ = "Using innodb_support_xa is deprecated and the"
+ " parameter may be removed in future releases."
+ " Only innodb_support_xa=ON is allowed.";
+
+/** Update the session variable innodb_support_xa.
+@param[in] thd current session
+@param[in] var the system variable innodb_support_xa
+@param[in,out] var_ptr the contents of the variable
+@param[in] save the to-be-updated value */
+static
+void
+innodb_support_xa_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save)
+{
+ my_bool innodb_support_xa = *static_cast<const my_bool*>(save);
+
+ push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_WRONG_COMMAND,
+ innodb_support_xa
+ ? deprecated_innodb_support_xa
+ : deprecated_innodb_support_xa_off);
+}
+
static MYSQL_THDVAR_BOOL(support_xa, PLUGIN_VAR_OPCMDARG,
"Enable InnoDB support for the XA two-phase commit",
- NULL, NULL, TRUE);
+ /* check_func */ NULL, innodb_support_xa_update,
+ /* default */ TRUE);
static MYSQL_THDVAR_BOOL(table_locks, PLUGIN_VAR_OPCMDARG,
"Enable InnoDB locking in LOCK TABLES",
@@ -970,9 +930,6 @@ static MYSQL_THDVAR_STR(ft_user_stopword_table,
"User supplied stopword table name, effective in the session level.",
innodb_stopword_table_validate, NULL, NULL);
-/* JAN: TODO: MySQL 5.7 */
-#define SHOW_SCOPE_GLOBAL 0
-
static MYSQL_THDVAR_STR(tmpdir,
PLUGIN_VAR_OPCMDARG|PLUGIN_VAR_MEMALLOC,
"Directory for temporary non-tablespace files.",
@@ -1101,6 +1058,7 @@ static SHOW_VAR innodb_status_variables[]= {
{"ahi_drop_lookups",
(char*) &export_vars.innodb_ahi_drop_lookups, SHOW_LONG},
#endif /* UNIV_DEBUG */
+
/* Status variables for page compression */
{"page_compression_saved",
(char*) &export_vars.innodb_page_compression_saved, SHOW_LONGLONG},
@@ -1206,6 +1164,7 @@ static SHOW_VAR innodb_status_variables[]= {
{"scrub_background_page_split_failures_unknown",
(char*) &export_vars.innodb_scrub_page_split_failures_unknown,
SHOW_LONG},
+
{NullS, NullS, SHOW_LONG}
};
@@ -1237,6 +1196,7 @@ innobase_close_connection(
THD* thd); /*!< in: MySQL thread handle for
which to close the connection */
+#ifdef MYSQL_KILL_CONNECTION
/*****************************************************************//**
Cancel any pending lock request associated with the current THD. */
static
@@ -1246,6 +1206,7 @@ innobase_kill_connection(
handlerton* hton, /*!< in/out: InnoDB handlerton */
THD* thd); /*!< in: MySQL thread handle for
which to close the connection */
+#endif /* MYSQL_KILL_CONNECTION */
static void innobase_kill_query(handlerton *hton, THD* thd, enum thd_kill_levels level);
static void innobase_commit_ordered(handlerton *hton, THD* thd, bool all);
@@ -1438,6 +1399,7 @@ innobase_rollback_by_xid(
XID* xid); /*!< in: X/Open XA transaction
identification */
+#ifdef MYSQL_TABLESPACES
/** This API handles CREATE, ALTER & DROP commands for InnoDB tablespaces.
@param[in] hton Handlerton of InnoDB
@param[in] thd Connection
@@ -1449,6 +1411,7 @@ innobase_alter_tablespace(
handlerton* hton,
THD* thd,
st_alter_tablespace* alter_info);
+#endif /* MYSQL_TABLESPACES */
/** Remove all tables in the named database inside InnoDB.
@param[in] hton handlerton from InnoDB
@@ -1484,6 +1447,7 @@ innobase_start_trx_and_assign_read_view(
THD* thd); /* in: MySQL thread handle of the
user for whom the transaction should
be committed */
+
/** Flush InnoDB redo logs to the file system.
@param[in] hton InnoDB handlerton
@param[in] binlog_group_flush true if we got invoked by binlog
@@ -1492,17 +1456,35 @@ group commit during flush stage, false in other cases.
static
bool
innobase_flush_logs(
- handlerton* hton, /*!< in: InnoDB handlerton */
- bool binlog_group_flush);
-/** Flush InnoDB redo logs to the file system.
-@param[in] hton InnoDB handlerton
-@param[in] binlog_group_flush true if we got invoked by binlog
-group commit during flush stage, false in other cases.
-@return false */
-static
-bool
-innobase_flush_logs(
- handlerton* hton); /*!< in: InnoDB handlerton */
+ handlerton* hton,
+ bool binlog_group_flush)
+{
+ DBUG_ENTER("innobase_flush_logs");
+ DBUG_ASSERT(hton == innodb_hton_ptr);
+
+ if (srv_read_only_mode) {
+ DBUG_RETURN(false);
+ }
+
+ /* If !binlog_group_flush, we got invoked by FLUSH LOGS or similar.
+ Else, we got invoked by binlog group commit during flush stage. */
+
+ if (binlog_group_flush && srv_flush_log_at_trx_commit == 0) {
+ /* innodb_flush_log_at_trx_commit=0
+ (write and sync once per second).
+ Do not flush the redo log during binlog group commit. */
+ DBUG_RETURN(false);
+ }
+
+ /* Flush the redo log buffer to the redo log file.
+ Sync it to disc if we are in FLUSH LOGS, or if
+ innodb_flush_log_at_trx_commit=1
+ (write and sync at each commit). */
+ log_buffer_flush_to_disk(!binlog_group_flush
+ || srv_flush_log_at_trx_commit == 1);
+
+ DBUG_RETURN(false);
+}
/** Flush InnoDB redo logs to the file system.
@param[in] hton InnoDB handlerton
@@ -1578,6 +1560,7 @@ innobase_fill_i_s_table(
return(ret);
}
+#ifdef MYSQL_STORE_FTS_DOC_ID
/** Store doc_id value into FTS_DOC_ID field
@param[in,out] tbl table containing FULLTEXT index
@param[in] doc_id FTS_DOC_ID value */
@@ -1590,11 +1573,11 @@ innobase_fts_store_docid(
my_bitmap_map* old_map
= dbug_tmp_use_all_columns(tbl, tbl->write_set);
- /* JAN: TODO: MySQL 5.7 */
- //tbl->fts_doc_id_field->store(static_cast<longlong>(doc_id), true);
+ tbl->fts_doc_id_field->store(static_cast<longlong>(doc_id), true);
dbug_tmp_restore_column_map(tbl->write_set, old_map);
}
+#endif
/*************************************************************//**
Check for a valid value of innobase_commit_concurrency.
@@ -1638,6 +1621,7 @@ innobase_create_handler(
TABLE_SHARE* table,
MEM_ROOT* mem_root)
{
+#ifdef MYSQL_INNODB_PARTITIONS
/* If the table:
1) have type InnoDB (not the generic partition handlerton)
2) have partitioning defined
@@ -1647,16 +1631,15 @@ innobase_create_handler(
&& table->db_type() == innodb_hton_ptr // 1)
&& table->partition_info_str // 2)
&& table->partition_info_str_len) { // 2)
- /* JAN: TODO: MySQL 5.7 InnoDB Partitioning disabled
ha_innopart* file = new (mem_root) ha_innopart(hton, table);
if (file && file->init_partitioning(mem_root))
{
delete file;
return(NULL);
}
- return(file);*/
- return (NULL);
+ return(file);
}
+#endif
return(new (mem_root) ha_innobase(hton, table));
}
@@ -1950,19 +1933,6 @@ thd_is_select(
}
/******************************************************************//**
-Returns true if the thread supports XA,
-global value of innodb_supports_xa if thd is NULL.
-@return true if thd has XA support */
-ibool
-thd_supports_xa(
-/*============*/
- THD* thd) /*!< in: thread handle, or NULL to query
- the global innodb_supports_xa */
-{
- return(THDVAR(thd, support_xa));
-}
-
-/******************************************************************//**
Returns the lock wait timeout for the current connection.
@return the lock wait timeout, in seconds */
ulong
@@ -1989,10 +1959,34 @@ thd_set_lock_wait_time(
}
}
+/** Get the value of innodb_tmpdir.
+@param[in] thd thread handle, or NULL to query
+ the global innodb_tmpdir.
+@retval NULL if innodb_tmpdir="" */
+const char*
+thd_innodb_tmpdir(
+ THD* thd)
+{
+
+#ifdef UNIV_DEBUG
+ trx_t* trx = thd_to_trx(thd);
+ btrsea_sync_check check(trx->has_search_latch);
+ ut_ad(!sync_check_iterate(check));
+#endif /* UNIV_DEBUG */
+
+ const char* tmp_dir = THDVAR(thd, tmpdir);
+
+ if (tmp_dir != NULL && *tmp_dir == '\0') {
+ tmp_dir = NULL;
+ }
+
+ return(tmp_dir);
+}
+
/** Obtain the private handler of InnoDB session specific data.
@param[in,out] thd MySQL thread handler.
@return reference to private handler */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
static
innodb_session_t*&
thd_to_innodb_session(
@@ -2015,7 +2009,7 @@ thd_to_innodb_session(
/** Obtain the InnoDB transaction of a MySQL thread.
@param[in,out] thd MySQL thread handler.
@return reference to transaction pointer */
-MY_ATTRIBUTE((warn_unused_result, nonnull))
+MY_ATTRIBUTE((warn_unused_result))
trx_t*&
thd_to_trx(
THD* thd)
@@ -2026,6 +2020,19 @@ thd_to_trx(
return(innodb_session->m_trx);
}
+#ifdef WITH_WSREP
+/********************************************************************//**
+Obtain the InnoDB transaction id of a MySQL thread.
+@return transaction id */
+__attribute__((warn_unused_result, nonnull))
+ulonglong
+thd_to_trx_id(
+ THD* thd) /*!< in: MySQL thread */
+{
+ return(thd_to_trx(thd)->id);
+}
+#endif /* WITH_WSREP */
+
/** Check if statement is of type INSERT .... SELECT that involves
use of intrinsic tables.
@param[in] thd thread handler
@@ -2067,20 +2074,6 @@ add_table_to_thread_cache(
priv->register_table_handler(table->name.m_name, table);
}
-#ifdef WITH_WSREP
-/********************************************************************//**
-Obtain the InnoDB transaction id of a MySQL thread.
-@return transaction id */
-__attribute__((warn_unused_result, nonnull))
-ulonglong
-thd_to_trx_id(
-/*=======*/
- THD* thd) /*!< in: MySQL thread */
-{
- return(thd_to_trx(thd)->id);
-}
-#endif /* WITH_WSREP */
-
/********************************************************************//**
Call this function when mysqld passes control to the client. That is to
avoid deadlocks on the adaptive hash S-latch possibly held by thd. For more
@@ -2158,11 +2151,9 @@ convert_error_code_to_mysql(
"depth of %d. Please "
"drop extra constraints and try "
"again", DICT_FK_MAX_RECURSIVE_LOAD);
- return(-1);; /* unspecified error */
- /* JAN: TODO: MySQL 5.7
+
my_error(ER_FK_DEPTH_EXCEEDED, MYF(0), FK_MAX_CASCADE_DEL);
return(HA_ERR_FK_DEPTH_EXCEEDED);
- */
case DB_CANT_CREATE_GEOMETRY_OBJECT:
my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
@@ -2212,7 +2203,7 @@ convert_error_code_to_mysql(
if (thd) {
thd_mark_transaction_to_rollback(
- thd, (int) row_rollback_on_timeout);
+ thd, (bool) row_rollback_on_timeout);
}
return(HA_ERR_LOCK_WAIT_TIMEOUT);
@@ -2223,6 +2214,7 @@ convert_error_code_to_mysql(
case DB_ROW_IS_REFERENCED:
return(HA_ERR_ROW_IS_REFERENCED);
+ case DB_NO_FK_ON_S_BASE_COL:
case DB_CANNOT_ADD_CONSTRAINT:
case DB_CHILD_NO_INDEX:
case DB_PARENT_NO_INDEX:
@@ -2260,10 +2252,7 @@ convert_error_code_to_mysql(
return(HA_ERR_DECRYPTION_FAILED);
case DB_TABLESPACE_NOT_FOUND:
- /* JAN: TODO: MySQL 5.7
return(HA_ERR_TABLESPACE_MISSING);
- */
- return(HA_ERR_NO_SUCH_TABLE);
case DB_TOO_BIG_RECORD: {
/* If prefix is true then a 768-byte prefix is stored
@@ -2325,29 +2314,17 @@ convert_error_code_to_mysql(
case DB_TABLESPACE_EXISTS:
return(HA_ERR_TABLESPACE_EXISTS);
case DB_TABLESPACE_DELETED:
- /* JAN: TODO: MySQL 5.7
return(HA_ERR_TABLESPACE_MISSING);
- */
- return(HA_ERR_NO_SUCH_TABLE);
case DB_IDENTIFIER_TOO_LONG:
return(HA_ERR_INTERNAL_ERROR);
case DB_TABLE_CORRUPT:
- /* JAN: TODO: MySQL 5.7
return(HA_ERR_TABLE_CORRUPT);
- */
- return(HA_ERR_INTERNAL_ERROR);
case DB_FTS_TOO_MANY_WORDS_IN_PHRASE:
return(HA_ERR_FTS_TOO_MANY_WORDS_IN_PHRASE);
case DB_WRONG_FILE_NAME:
- /* JAN: TODO: MySQL 5.7
return(HA_ERR_WRONG_FILE_NAME);
- */
- return(HA_ERR_INTERNAL_ERROR);
case DB_COMPUTE_VALUE_FAILED:
- /* JAN: TODO: MySQL 5.7
return(HA_ERR_COMPUTE_FAILED);
- */
- return(HA_ERR_INTERNAL_ERROR);
}
}
@@ -2549,7 +2526,7 @@ Thread unsafe, can only be called from the thread owning the THD.
@return SQL statement string */
const char*
innobase_get_stmt_unsafe(
-/*==============*/
+/*=====================*/
THD* thd,
size_t* length)
{
@@ -2557,6 +2534,8 @@ innobase_get_stmt_unsafe(
const char* query=NULL;
stmt = thd_query_string(thd);
+ // MySQL 5.7
+ //stmt = thd_query_unsafe(thd);
if (stmt && stmt->str) {
*length = stmt->length;
@@ -2577,7 +2556,7 @@ into the provided buffer.
@return Length of the SQL statement */
size_t
innobase_get_stmt_safe(
-/*==============*/
+/*===================*/
THD* thd,
char* buf,
size_t buflen)
@@ -2625,12 +2604,73 @@ innobase_get_lower_case_table_names(void)
return(lower_case_table_names);
}
-/*********************************************************************//**
-Creates a temporary file.
+/**
+ Test a file path whether it is same as mysql data directory path.
+
+ @param path null terminated character string
+
+ @return
+ @retval TRUE The path is different from mysql data directory.
+ @retval FALSE The path is same as mysql data directory.
+*/
+static bool is_mysql_datadir_path(const char *path)
+{
+ if (path == NULL)
+ return false;
+
+ char mysql_data_dir[FN_REFLEN], path_dir[FN_REFLEN];
+ convert_dirname(path_dir, path, NullS);
+ convert_dirname(mysql_data_dir, mysql_unpacked_real_data_home, NullS);
+ size_t mysql_data_home_len= dirname_length(mysql_data_dir);
+ size_t path_len = dirname_length(path_dir);
+
+ if (path_len < mysql_data_home_len)
+ return true;
+
+ if (!lower_case_file_system)
+ return(memcmp(mysql_data_dir, path_dir, mysql_data_home_len));
+
+ return(files_charset_info->coll->strnncoll(files_charset_info,
+ (uchar *) path_dir, path_len,
+ (uchar *) mysql_data_dir,
+ mysql_data_home_len,
+ TRUE));
+}
+
+static int mysql_tmpfile_path(const char *path, const char *prefix)
+{
+ DBUG_ASSERT(path != NULL);
+ DBUG_ASSERT((strlen(path) + strlen(prefix)) <= FN_REFLEN);
+
+ char filename[FN_REFLEN];
+ File fd = create_temp_file(filename, path, prefix,
+#ifdef __WIN__
+ O_BINARY | O_TRUNC | O_SEQUENTIAL |
+ O_SHORT_LIVED |
+#endif /* __WIN__ */
+ O_CREAT | O_EXCL | O_RDWR | O_TEMPORARY,
+ MYF(MY_WME));
+ if (fd >= 0) {
+#ifndef __WIN__
+ /*
+ This can be removed once the following bug is fixed:
+ Bug #28903 create_temp_file() doesn't honor O_TEMPORARY option
+ (file not removed) (Unix)
+ */
+ unlink(filename);
+#endif /* !__WIN__ */
+ }
+
+ return fd;
+}
+
+/** Creates a temporary file in the location specified by the parameter
+path. If the path is NULL, then it will be created in tmpdir.
+@param[in] path location for creating temporary file
@return temporary file descriptor, or < 0 on error */
int
-innobase_mysql_tmpfile(void)
-/*========================*/
+innobase_mysql_tmpfile(
+ const char* path)
{
#ifdef WITH_INNODB_DISALLOW_WRITES
os_event_wait(srv_allow_writes_event);
@@ -2643,7 +2683,11 @@ innobase_mysql_tmpfile(void)
return(-1);
);
- fd = mysql_tmpfile("ib");
+ if (path == NULL) {
+ fd = mysql_tmpfile("ib");
+ } else {
+ fd = mysql_tmpfile_path(path, "ib");
+ }
if (fd >= 0) {
/* Copy the file descriptor, so that the additional resources
@@ -2683,9 +2727,9 @@ innobase_mysql_tmpfile(void)
set_my_errno(errno);
my_strerror(errbuf, sizeof(errbuf), my_errno);
my_error(EE_OUT_OF_FILERESOURCES,
- MYF(ME_BELL+ME_WAITTANG),
- "ib*", my_errno,
- errbuf);
+ MYF(0),
+ "ib*", my_errno,
+ errbuf);
}
my_close(fd, MYF(MY_WME));
}
@@ -2752,6 +2796,7 @@ innobase_raw_format(
return(ut_str_sql_format(buf_tmp, buf_tmp_used, buf, buf_size));
}
+#ifdef MYSQL_COMPRESSION
/** Check if the string is "empty" or "none".
@param[in] algorithm Compression algorithm to check
@return true if no algorithm requested */
@@ -2759,7 +2804,9 @@ bool
Compression::is_none(const char* algorithm)
{
/* NULL is the same as NONE */
- if (algorithm == NULL || innobase_strcasecmp(algorithm, "none") == 0) {
+ if (algorithm == NULL
+ || *algorithm == 0
+ || innobase_strcasecmp(algorithm, "none") == 0) {
return(true);
}
@@ -2805,6 +2852,61 @@ Compression::validate(const char* algorithm)
return(check(algorithm, &compression));
}
+#endif /* MYSQL_COMPRESSION */
+
+#ifdef MYSQL_ENCRYPTION
+/** Check if the string is "" or "n".
+@param[in] algorithm Encryption algorithm to check
+@return true if no algorithm requested */
+bool
+Encryption::is_none(const char* algorithm)
+{
+ /* NULL is the same as NONE */
+ if (algorithm == NULL
+ || innobase_strcasecmp(algorithm, "n") == 0
+ || innobase_strcasecmp(algorithm, "") == 0) {
+ return(true);
+ }
+
+ return(false);
+}
+
+/** Check the encryption option and set it
+@param[in] option encryption option
+@param[in/out] encryption The encryption algorithm
+@return DB_SUCCESS or DB_UNSUPPORTED */
+dberr_t
+Encryption::set_algorithm(
+ const char* option,
+ Encryption* encryption)
+{
+ if (is_none(option)) {
+
+ encryption->m_type = NONE;
+
+ } else if (innobase_strcasecmp(option, "y") == 0) {
+
+ encryption->m_type = AES;
+
+ } else {
+ return(DB_UNSUPPORTED);
+ }
+
+ return(DB_SUCCESS);
+}
+
+/** Check for supported ENCRYPT := (Y | N) supported values
+@param[in] option Encryption option
+@param[out] encryption The encryption algorithm
+@return DB_SUCCESS or DB_UNSUPPORTED */
+dberr_t
+Encryption::validate(const char* option)
+{
+ Encryption encryption;
+
+ return(encryption.set_algorithm(option, &encryption));
+}
+#endif /* MYSQL_ENCRYPTION */
/*********************************************************************//**
Compute the next autoinc value.
@@ -3049,6 +3151,7 @@ check_trx_exists(
return(trx);
}
+#ifdef MYSQL_REPLACE_TRX_IN_THD
/** InnoDB transaction object that is currently associated with THD is
replaced with that of the 2nd argument. The previous value is
returned through the 3rd argument's buffer, unless it's NULL. When
@@ -3088,6 +3191,7 @@ innodb_replace_trx_in_thd(
}
trx = static_cast<trx_t*>(new_trx_arg);
}
+#endif /* MYSQL_REPLACE_TRX_IN_THD */
/*********************************************************************//**
Note that a transaction has been registered with MySQL.
@@ -3095,7 +3199,7 @@ Note that a transaction has been registered with MySQL.
static inline
bool
trx_is_registered_for_2pc(
-/*=========================*/
+/*======================*/
const trx_t* trx) /* in: transaction */
{
return(trx->is_registered == 1);
@@ -3106,7 +3210,7 @@ Note that innobase_commit_ordered() was run. */
static inline
void
trx_set_active_commit_ordered(
-/*==============================*/
+/*==========================*/
trx_t* trx) /* in: transaction */
{
ut_a(trx_is_registered_for_2pc(trx));
@@ -3553,6 +3657,32 @@ innobase_quote_identifier(
}
}
+/** Quote a standard SQL identifier like tablespace, index or column name.
+@param[in] trx InnoDB transaction, or NULL
+@param[in] id identifier to quote
+@return quoted identifier */
+std::string
+innobase_quote_identifier(
+/*======================*/
+ trx_t* trx,
+ const char* id)
+{
+ std::string quoted_identifier;
+ const int q = trx != NULL && trx->mysql_thd != NULL
+ ? get_quote_char_for_identifier(trx->mysql_thd, id, strlen(id))
+ : '`';
+
+ if (q == EOF) {
+ quoted_identifier.append(id);
+ } else {
+ quoted_identifier += (unsigned char)q;
+ quoted_identifier.append(id);
+ quoted_identifier += (unsigned char)q;
+ }
+
+ return (quoted_identifier);
+}
+
/** Convert a table name to the MySQL system_charset_info (UTF-8)
and quote it.
@param[out] buf buffer for converted identifier
@@ -3654,7 +3784,7 @@ trx_is_interrupted(
/*===============*/
const trx_t* trx) /*!< in: transaction */
{
- return(trx && trx->mysql_thd && thd_kill_level(trx->mysql_thd));
+ return(trx && trx->mysql_thd && thd_kill_level(trx->mysql_thd));
}
/**********************************************************************//**
@@ -3678,9 +3808,17 @@ ha_innobase::reset_template(void)
ut_ad(m_prebuilt->magic_n == ROW_PREBUILT_ALLOCATED);
ut_ad(m_prebuilt->magic_n2 == m_prebuilt->magic_n);
+ /* Force table to be freed in close_thread_table(). */
+ DBUG_EXECUTE_IF("free_table_in_fts_query",
+ if (m_prebuilt->in_fts_query) {
+ table->m_needs_reopen = true;
+ }
+ );
+
m_prebuilt->keep_other_fields_on_keyread = 0;
m_prebuilt->read_just_key = 0;
m_prebuilt->in_fts_query = 0;
+
/* Reset index condition pushdown state. */
if (m_prebuilt->idx_cond) {
m_prebuilt->idx_cond = NULL;
@@ -3797,6 +3935,7 @@ system tables in InnoDB. Please don't add any SE-specific system tables here.
layer system table.
*/
+#ifdef MYSQL_IS_SUPPORTED_SYSTEM_TABLE
static bool innobase_is_supported_system_table(const char *db,
const char *table_name,
bool is_sql_layer_system_table)
@@ -3825,6 +3964,67 @@ static bool innobase_is_supported_system_table(const char *db,
return false;
}
+#endif /* MYSQL_IS_SUPPORTED_SYSTEM_TABLE */
+
+#ifdef MYSQL_ENCRYPTION
+/* mutex protecting the master_key_id */
+ib_mutex_t master_key_id_mutex;
+
+/** Rotate the encrypted tablespace keys according to master key
+rotation.
+@return false on success, true on failure */
+bool
+innobase_encryption_key_rotation()
+{
+ byte* master_key = NULL;
+ bool ret = FALSE;
+
+ /* Require the mutex to block other rotate request. */
+ mutex_enter(&master_key_id_mutex);
+
+ /* Check if keyring loaded and the currently master key
+ can be fetched. */
+ if (Encryption::master_key_id != 0) {
+ ulint master_key_id;
+ Encryption::Version version;
+
+ Encryption::get_master_key(&master_key_id,
+ &master_key,
+ &version);
+ if (master_key == NULL) {
+ mutex_exit(&master_key_id_mutex);
+ my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+ return(true);
+ }
+ my_free(master_key);
+ }
+
+ master_key = NULL;
+
+ /* Generate the new master key. */
+ Encryption::create_master_key(&master_key);
+
+ if (master_key == NULL) {
+ my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+ mutex_exit(&master_key_id_mutex);
+ return(true);
+ }
+
+ ret = !fil_encryption_rotate();
+
+ my_free(master_key);
+
+ /* If rotation failure, return error */
+ if (ret) {
+ my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+ }
+
+ /* Release the mutex. */
+ mutex_exit(&master_key_id_mutex);
+
+ return(ret);
+}
+#endif /* MYSQL_ENCRYPTION */
/** Return partitioning flags. */
static uint innobase_partition_flags()
@@ -3922,11 +4122,17 @@ innobase_init(
innobase_hton->commit_by_xid = innobase_commit_by_xid;
innobase_hton->rollback_by_xid = innobase_rollback_by_xid;
innobase_hton->commit_checkpoint_request=innobase_checkpoint_request;
+
+#ifdef INNOBASE_CURSOR_VIEW
innobase_hton->create_cursor_read_view = innobase_create_cursor_view;
innobase_hton->set_cursor_read_view = innobase_set_cursor_view;
innobase_hton->close_cursor_read_view = innobase_close_cursor_view;
+#endif
innobase_hton->create = innobase_create_handler;
+
+#ifdef MYSQL_TABLESPACES
innobase_hton->alter_tablespace = innobase_alter_tablespace;
+#endif
innobase_hton->drop_database = innobase_drop_database;
innobase_hton->panic = innobase_end;
innobase_hton->partition_flags= innobase_partition_flags;
@@ -3942,10 +4148,12 @@ innobase_init(
innobase_hton->release_temporary_latches =
innobase_release_temporary_latches;
- /* JAN: TODO: MySQL 5.7
+
+#ifdef MYSQL_REPLACE_TRX_IN_THD
innobase_hton->replace_native_transaction_in_thd =
innodb_replace_trx_in_thd;
- */
+#endif
+
#ifdef WITH_WSREP
innobase_hton->abort_transaction=wsrep_abort_transaction;
innobase_hton->set_checkpoint=innobase_wsrep_set_checkpoint;
@@ -3953,21 +4161,28 @@ innobase_init(
innobase_hton->fake_trx_id=wsrep_fake_trx_id;
#endif /* WITH_WSREP */
- if (srv_file_per_table)
- innobase_hton->tablefile_extensions = ha_innobase_exts;
+ if (srv_file_per_table) {
+ innobase_hton->tablefile_extensions = ha_innobase_exts;
+ }
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_INNODB_API_CB
+ /* JAN: TODO: MySQL 5.7 */
innobase_hton->data = &innodb_api_cb;
- */
+#endif
innobase_hton->table_options = innodb_table_option_list;
innodb_remember_check_sysvar_funcs();
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_IS_SUPPORTED_SYSTEM_TABLE
innobase_hton->is_supported_system_table=
innobase_is_supported_system_table;
- */
+#endif
+
+#ifdef MYSQL_ENCRYPTION
+ innobase_hton->rotate_encryption_master_key =
+ innobase_encryption_key_rotation;
+#endif
ut_a(DATA_MYSQL_TRUE_VARCHAR == (ulint)MYSQL_TYPE_VARCHAR);
@@ -4007,6 +4222,7 @@ innobase_init(
/* Setup the memory alloc/free tracing mechanisms before calling
any functions that could possibly allocate memory. */
ut_new_boot();
+
if (UNIV_PAGE_SIZE != UNIV_PAGE_SIZE_DEF) {
fprintf(stderr,
"InnoDB: Warning: innodb_page_size has been "
@@ -4177,7 +4393,7 @@ innobase_init(
srv_undo_dir = default_path;
}
- os_normalize_path_for_win(srv_undo_dir);
+ os_normalize_path(srv_undo_dir);
if (strchr(srv_undo_dir, ';')) {
sql_print_error("syntax error in innodb_undo_directory");
@@ -4203,6 +4419,11 @@ innobase_init(
ib::warn() << deprecated_large_prefix;
}
+ if (!THDVAR(NULL, support_xa)) {
+ ib::warn() << deprecated_innodb_support_xa_off;
+ THDVAR(NULL, support_xa) = TRUE;
+ }
+
if (innobase_file_format_name != innodb_file_format_default) {
ib::warn() << deprecated_file_format;
}
@@ -4400,16 +4621,18 @@ innobase_change_buffering_inited_ok:
if (innobase_open_files < 10) {
innobase_open_files = 300;
- if (srv_file_per_table && tc_size > 300) {
+ if (srv_file_per_table && tc_size > 300 && tc_size < open_files_limit) {
innobase_open_files = tc_size;
}
}
- if (innobase_open_files > (long) tc_size) {
- fprintf(stderr,
- "innodb_open_files should not be greater"
- " than the open_files_limit.\n");
- innobase_open_files = tc_size;
+ if (innobase_open_files > (long) open_files_limit) {
+ ib::warn() << "innodb_open_files " << innobase_open_files
+ << " should not be greater"
+ << "than the open_files_limit " << open_files_limit;
+ if (innobase_open_files > (long) tc_size) {
+ innobase_open_files = tc_size;
+ }
}
srv_max_n_open_files = (ulint) innobase_open_files;
@@ -4433,15 +4656,12 @@ innobase_change_buffering_inited_ok:
data_mysql_default_charset_coll = (ulint) default_charset_info->number;
innobase_commit_concurrency_init_default();
-
#ifdef HAVE_POSIX_FALLOCATE
srv_use_posix_fallocate = (ibool) innobase_use_fallocate;
#endif
srv_use_atomic_writes = (ibool) innobase_use_atomic_writes;
-
if (innobase_use_atomic_writes) {
fprintf(stderr, "InnoDB: using atomic writes.\n");
-
/* Force doublewrite buffer off, atomic writes replace it. */
if (srv_use_doublewrite_buf) {
fprintf(stderr, "InnoDB: Switching off doublewrite buffer "
@@ -4451,7 +4671,7 @@ innobase_change_buffering_inited_ok:
/* Force O_DIRECT on Unixes (on Windows writes are always unbuffered)*/
#ifndef _WIN32
- if(!innobase_file_flush_method ||
+ if (!innobase_file_flush_method ||
!strstr(innobase_file_flush_method, "O_DIRECT")) {
innobase_file_flush_method =
srv_file_flush_method_str = (char*)"O_DIRECT";
@@ -4535,6 +4755,11 @@ innobase_change_buffering_inited_ok:
DBUG_RETURN(innobase_init_abort());
}
+#ifdef MYSQL_ENCRYPTION
+ /* Create mutex to protect encryption master_key_id. */
+ mutex_create(LATCH_ID_MASTER_KEY_ID_MUTEX, &master_key_id_mutex);
+#endif
+
/* Adjust the innodb_undo_logs config object */
innobase_undo_logs_init_default_max();
@@ -4638,6 +4863,9 @@ innobase_end(
hash_table_free(innobase_open_tables);
innobase_open_tables = NULL;
+#ifdef MYSQL_ENCRYPTION
+ mutex_free(&master_key_id_mutex);
+#endif
if (innobase_shutdown_for_mysql() != DB_SUCCESS) {
err = 1;
}
@@ -4653,44 +4881,6 @@ innobase_end(
DBUG_RETURN(err);
}
-/** Flush InnoDB redo logs to the file system.
-@param[in] hton InnoDB handlerton
-@param[in] binlog_group_flush true if we got invoked by binlog
-group commit during flush stage, false in other cases.
-@return false */
-static
-bool
-innobase_flush_logs(
- handlerton* hton,
- bool binlog_group_flush)
-{
- DBUG_ENTER("innobase_flush_logs");
- DBUG_ASSERT(hton == innodb_hton_ptr);
-
- if (srv_read_only_mode) {
- DBUG_RETURN(false);
- }
-
- /* If !binlog_group_flush, we got invoked by FLUSH LOGS or similar.
- Else, we got invoked by binlog group commit during flush stage. */
-
- if (binlog_group_flush && srv_flush_log_at_trx_commit == 0) {
- /* innodb_flush_log_at_trx_commit=0
- (write and sync once per second).
- Do not flush the redo log during binlog group commit. */
- DBUG_RETURN(false);
- }
-
- /* Flush the redo log buffer to the redo log file.
- Sync it to disc if we are in FLUSH LOGS, or if
- innodb_flush_log_at_trx_commit=1
- (write and sync at each commit). */
- log_buffer_flush_to_disk(!binlog_group_flush
- || srv_flush_log_at_trx_commit == 1);
-
- DBUG_RETURN(false);
-}
-
/*****************************************************************//**
Commits a transaction in an InnoDB database. */
void
@@ -4783,7 +4973,7 @@ innobase_start_trx_and_assign_read_view(
static
void
innobase_commit_ordered_2(
-/*============*/
+/*======================*/
trx_t* trx, /*!< in: Innodb transaction */
THD* thd) /*!< in: MySQL thread handle */
{
@@ -4872,7 +5062,7 @@ the one handling the rest of the transaction. */
static
void
innobase_commit_ordered(
-/*============*/
+/*====================*/
handlerton *hton, /*!< in: Innodb handlerton */
THD* thd, /*!< in: MySQL thread handle of the user for whom
the transaction should be committed */
@@ -4892,7 +5082,7 @@ innobase_commit_ordered(
have an assert here.*/
ut_ad(!trx->has_search_latch);
- if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
+ if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
/* We cannot throw error here; instead we will catch this error
again in innobase_commit() and report it from there. */
DBUG_VOID_RETURN;
@@ -4937,7 +5127,10 @@ innobase_commit(
if (trx_in_innodb.is_aborted()) {
- DBUG_RETURN(innobase_rollback(hton, thd, commit_trx));
+ innobase_rollback(hton, thd, commit_trx);
+
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, thd));
}
ut_ad(trx->dict_operation_lock_mode == 0);
@@ -4955,6 +5148,7 @@ innobase_commit(
}
bool read_only = trx->read_only || trx->id == 0;
+ DBUG_PRINT("info", ("readonly: %d", read_only));
if (commit_trx
|| (!thd_test_options(thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
@@ -4965,6 +5159,7 @@ innobase_commit(
/* Run the fast part of commit if we did not already. */
if (!trx_is_active_commit_ordered(trx)) {
innobase_commit_ordered_2(trx, thd);
+
}
/* We were instructed to commit the whole transaction, or
@@ -4975,11 +5170,14 @@ innobase_commit(
this one, to allow then to group commit with us. */
thd_wakeup_subsequent_commits(thd, 0);
+ if (!read_only) {
+ trx->flush_log_later = false;
+ }
+
/* Now do a write + flush of logs. */
trx_commit_complete_for_mysql(trx);
trx_deregister_from_2pc(trx);
-
} else {
/* We just mark the SQL statement ended and do not do a
transaction commit */
@@ -5062,7 +5260,7 @@ innobase_rollback(
error = trx_rollback_for_mysql(trx);
if (trx->state == TRX_STATE_FORCED_ROLLBACK) {
-
+#ifdef UNIV_DEBUG
char buffer[1024];
/* JAN: TODO: MySQL 5.7
@@ -5073,18 +5271,12 @@ innobase_rollback(
*/
thd_get_error_context_description(thd, buffer,
sizeof(buffer), 512);
-
- error = DB_FORCED_ABORT;
+#endif /* UNIV_DEBUG */
trx->state = TRX_STATE_NOT_STARTED;
}
trx_deregister_from_2pc(trx);
-
- } else if (trx_in_innodb.is_aborted()) {
-
- error = DB_FORCED_ABORT;
-
} else {
error = trx_rollback_last_sql_stat_for_mysql(trx);
@@ -5207,7 +5399,7 @@ checkpoint when necessary.*/
UNIV_INTERN
void
innobase_mysql_log_notify(
-/*===============*/
+/*======================*/
ib_uint64_t write_lsn, /*!< in: LSN written to log file */
ib_uint64_t flush_lsn) /*!< in: LSN flushed to disk */
{
@@ -5336,7 +5528,7 @@ innobase_rollback_to_savepoint_can_release_mdl(
TrxInInnoDB trx_in_innodb(trx);
- /* If transaction has not acquired any locks then it is safe
+ /* If transaction has not acquired any locks then it is safe
to release MDL after rollback to savepoint */
if (UT_LIST_GET_LEN(trx->lock.trx_locks) == 0) {
@@ -5441,38 +5633,87 @@ innobase_close_connection(
DBUG_ASSERT(hton == innodb_hton_ptr);
trx_t* trx = thd_to_trx(thd);
+ bool free_trx = false;
+
+ /* During server initialization MySQL layer will try to open
+ some of the master-slave tables those residing in InnoDB.
+ After MySQL layer is done with needed checks these tables
+ are closed followed by invocation of close_connection on the
+ associated thd.
+
+ close_connection rolls back the trx and then frees it.
+ Once trx is freed thd should avoid maintaining reference to
+ it else it can be classified as stale reference.
+
+ Re-invocation of innodb_close_connection on same thd should
+ get trx as NULL. */
if (trx) {
TrxInInnoDB trx_in_innodb(trx);
+ if (trx_in_innodb.is_aborted()) {
+
+ while (trx_is_started(trx)) {
+
+ os_thread_sleep(20);
+ }
+ }
+
if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
sql_print_error("Transaction not registered for MySQL 2PC, "
"but transaction is active");
}
- if (trx_is_started(trx) && global_system_variables.log_warnings) {
-
+ /* Disconnect causes rollback in the following cases:
+ - trx is not started, or
+ - trx is in *not* in PREPARED state, or
+ - trx has not updated any persistent data.
+ TODO/FIXME: it does not make sense to initiate rollback
+ in the 1st and 3rd case. */
+ if (trx_is_started(trx)) {
+ if (trx_state_eq(trx, TRX_STATE_PREPARED)) {
+ if (trx_is_redo_rseg_updated(trx)) {
+ trx_disconnect_prepared(trx);
+ } else {
+ trx_rollback_for_mysql(trx);
+ trx_deregister_from_2pc(trx);
+ free_trx = true;
+ }
+ } else {
sql_print_warning(
"MySQL is closing a connection that has an active "
"InnoDB transaction. " TRX_ID_FMT " row modifications "
"will roll back.",
- trx->undo_no);
+ " row modifications will roll back.",
+ trx->undo_no);
+ ut_d(ib::warn()
+ << "trx: " << trx << " started on: "
+ << innobase_basename(trx->start_file)
+ << ":" << trx->start_line);
+ innobase_rollback_trx(trx);
+ free_trx = true;
+ }
+ } else {
+ innobase_rollback_trx(trx);
+ free_trx = true;
}
+ }
- innobase_rollback_trx(trx);
-
+ /* Free trx only after TrxInInnoDB is deleted. */
+ if (free_trx) {
trx_free_for_mysql(trx);
+ }
- UT_DELETE(thd_to_innodb_session(thd));
+ UT_DELETE(thd_to_innodb_session(thd));
- thd_to_innodb_session(thd) = NULL;
- }
+ thd_to_innodb_session(thd) = NULL;
DBUG_RETURN(0);
}
+#ifdef MYSQL_KILL_CONNECTION
/*****************************************************************//**
Cancel any pending lock request associated with the current THD. */
static
@@ -5491,11 +5732,17 @@ innobase_kill_connection(
if (trx != NULL) {
/* Cancel a pending lock request if there are any */
- lock_trx_handle_wait(trx, false, false);
+ dberr_t err = lock_trx_handle_wait(trx, false, false);
+
+ if (err != DB_SUCCESS && err != DB_LOCK_WAIT) {
+ ib::warn() << "Killing connection failed " << ut_strerr(err) << "("<<err<<")";
+ }
+
}
DBUG_VOID_RETURN;
}
+#endif /* MYSQL_KILL_CONNECTION */
UNIV_INTERN void lock_cancel_waiting_and_release(lock_t* lock);
@@ -5504,10 +5751,10 @@ Cancel any pending lock request associated with the current THD. */
static
void
innobase_kill_query(
-/*======================*/
- handlerton* hton, /*!< in: innobase handlerton */
- THD* thd, /*!< in: MySQL thread being killed */
- enum thd_kill_levels level) /*!< in: kill level */
+/*================*/
+ handlerton* hton, /*!< in: innobase handlerton */
+ THD* thd, /*!< in: MySQL thread being killed */
+ enum thd_kill_levels level) /*!< in: kill level */
{
trx_t* trx;
@@ -5537,10 +5784,10 @@ innobase_kill_query(
bool trx_mutex_taken = false;
bool already_have_lock_mutex = false;
bool already_have_trx_mutex = false;
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
if (trx->lock.wait_lock) {
- WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id %lu ABORT %d thd %p"
+ WSREP_DEBUG("Killing victim trx %p BF %d trx BF %d trx_id " IB_ID_FMT " ABORT %d thd %p"
" current_thd %p BF %d",
trx, wsrep_thd_is_BF(trx->mysql_thd, FALSE),
wsrep_thd_is_BF(thd, FALSE),
@@ -5580,6 +5827,10 @@ innobase_kill_query(
ut_ad(trx_mutex_own(trx));
trx_mutex_exit(trx);
}
+
+ if (err != DB_SUCCESS && err != DB_LOCK_WAIT) {
+ ib::warn() << "Killing connection failed " << ut_strerr(err) << "("<<err<<")";
+ }
}
DBUG_VOID_RETURN;
@@ -5805,16 +6056,19 @@ Determines if the primary key is clustered index.
bool
ha_innobase::primary_key_is_clustered()
-/*=========================================*/
+/*===================================*/
{
return(true);
}
-/*********************************************************************
-Normalizes a table name string. A normalized name consists of the
-database name catenated to '/' and table name. An example:
-test/mytable. On Windows normalization puts both the database name and the
-table name always to lower case if "set_lower_case" is set to TRUE. */
+/** Normalizes a table name string.
+A normalized name consists of the database name catenated to '/'
+and table name. For example: test/mytable.
+On Windows, normalization puts both the database name and the
+table name always to lower case if "set_lower_case" is set to TRUE.
+@param[out] norm_name Normalized name, null-terminated.
+@param[in] name Name to normalize.
+@param[in] set_lower_case True if we also should fold to lower case. */
void
normalize_table_name_c_low(
/*=======================*/
@@ -6076,11 +6330,12 @@ innobase_match_index_columns(
mtype = innodb_idx_fld->col->mtype;
}
- // MariaDB-5.5 compatibility
- if ((key_part->field->real_type() == MYSQL_TYPE_ENUM ||
- key_part->field->real_type() == MYSQL_TYPE_SET) &&
- mtype == DATA_FIXBINARY)
- col_type= DATA_FIXBINARY;
+ /* MariaDB-5.5 compatibility */
+ if ((key_part->field->real_type() == MYSQL_TYPE_ENUM ||
+ key_part->field->real_type() == MYSQL_TYPE_SET) &&
+ mtype == DATA_FIXBINARY) {
+ col_type= DATA_FIXBINARY;
+ }
if (col_type != mtype) {
/* If the col_type we get from mysql type is a geometry
@@ -6116,6 +6371,7 @@ innobase_match_index_columns(
DBUG_RETURN(TRUE);
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
/** Build a template for a base column for a virtual column
@param[in] table MySQL TABLE
@param[in] clust_index InnoDB clustered index
@@ -6197,13 +6453,13 @@ is done when the table first opened.
@param[in,out] s_templ InnoDB template structure
@param[in] add_v new virtual columns added along with
add index call
-@param[in] locked true if innobase_share_mutex is held
+@param[in] locked true if dict_sys mutex is held
@param[in] share_tbl_name original MySQL table name */
void
innobase_build_v_templ(
const TABLE* table,
const dict_table_t* ib_table,
- innodb_col_templ_t* s_templ,
+ dict_vcol_templ_t* s_templ,
const dict_add_v_col_t* add_v,
bool locked,
const char* share_tbl_name)
@@ -6221,12 +6477,12 @@ innobase_build_v_templ(
ut_ad(n_v_col > 0);
if (!locked) {
- mysql_mutex_lock(&innobase_share_mutex);
+ mutex_enter(&dict_sys->mutex);
}
if (s_templ->vtempl) {
if (!locked) {
- mysql_mutex_unlock(&innobase_share_mutex);
+ mutex_exit(&dict_sys->mutex);
}
return;
}
@@ -6239,7 +6495,14 @@ innobase_build_v_templ(
s_templ->n_col = ncol;
s_templ->n_v_col = n_v_col;
s_templ->rec_len = table->s->stored_rec_length;
- s_templ->default_rec = table->s->default_values;
+ // JAN: MySQL 5.6
+ // s_templ->default_rec = table->s->default_values;
+
+ s_templ->default_rec = static_cast<byte*>(
+ ut_malloc_nokey(table->s->stored_rec_length));
+ memcpy(s_templ->default_rec, table->s->default_values,
+ table->s->stored_rec_length);
+
/* Mark those columns could be base columns */
for (ulint i = 0; i < ib_table->n_v_cols; i++) {
@@ -6334,24 +6597,17 @@ innobase_build_v_templ(
}
if (!locked) {
- mysql_mutex_unlock(&innobase_share_mutex);
+ mutex_exit(&dict_sys->mutex);
}
- ut_strlcpy(s_templ->db_name, table->s->db.str,
- table->s->db.length + 1);
- s_templ->db_name[table->s->db.length] = 0;
-
- ut_strlcpy(s_templ->tb_name, table->s->table_name.str,
- table->s->table_name.length + 1);
- s_templ->tb_name[table->s->table_name.length] = 0;
+ s_templ->db_name = table->s->db.str;
+ s_templ->tb_name = table->s->table_name.str;
if (share_tbl_name) {
- ulint s_len = strlen(share_tbl_name);
- ut_strlcpy(s_templ->share_name, share_tbl_name,
- s_len + 1);
- s_templ->tb_name[s_len] = 0;
+ s_templ->share_name = share_tbl_name;
}
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/*******************************************************************//**
This function builds a translation table in INNOBASE_SHARE
@@ -6577,6 +6833,7 @@ ha_innobase::innobase_initialize_autoinc()
auto_inc = field->get_max_int_value();
*/
auto_inc = innobase_get_int_col_max_value(field);
+ ut_ad(!innobase_is_v_fld(field));
/* autoinc column cannot be virtual column */
ut_ad(!innobase_is_v_fld(field));
@@ -6681,25 +6938,6 @@ ha_innobase::innobase_initialize_autoinc()
dict_table_autoinc_initialize(m_prebuilt->table, auto_inc);
}
-/** Free the virtual column template
-@param[in,out] vc_templ virtual column template */
-void
-free_vc_templ(
- innodb_col_templ_t* vc_templ)
-{
- if (vc_templ->vtempl) {
- ut_ad(vc_templ->n_v_col);
- for (ulint i = 0; i < vc_templ->n_col
- + vc_templ->n_v_col ; i++) {
- if (vc_templ->vtempl[i]) {
- ut_free(vc_templ->vtempl[i]);
- }
- }
- ut_free(vc_templ->vtempl);
- vc_templ->vtempl = NULL;
- }
-}
-
/*****************************************************************//**
Creates and opens a handle to a table which already exists in an InnoDB
database.
@@ -6782,7 +7020,7 @@ ha_innobase::open(
ib::warn() << "Table " << norm_name << " contains "
<< dict_table_get_n_user_cols(ib_table) << " user"
- " defined columns in InnoDB, but " << table->s->fields
+ " defined columns in InnoDB, but " << table->s->stored_fields
<< " columns in MySQL. Please check"
" INFORMATION_SCHEMA.INNODB_SYS_COLUMNS and " REFMAN
"innodb-troubleshooting.html for how to resolve the"
@@ -6796,6 +7034,28 @@ ha_innobase::open(
is_part = NULL;
}
+#ifdef MYSQL_ENCRYPTION
+ /* For encrypted table, check if the encryption info in data
+ file can't be retrieved properly, mark it as corrupted. */
+ if (ib_table != NULL
+ && dict_table_is_encrypted(ib_table)
+ && ib_table->ibd_file_missing
+ && !dict_table_is_discarded(ib_table)) {
+
+ /* Mark this table as corrupted, so the drop table
+ or force recovery can still use it, but not others. */
+
+ dict_table_close(ib_table, FALSE, FALSE);
+ ib_table = NULL;
+ is_part = NULL;
+
+ free_share(m_share);
+ my_error(ER_CANNOT_FIND_KEY_IN_KEYRING, MYF(0));
+
+ DBUG_RETURN(HA_ERR_TABLE_CORRUPT);
+ }
+#endif
+
if (NULL == ib_table) {
if (is_part) {
@@ -6860,26 +7120,6 @@ ha_innobase::open(
no_tablespace = false;
}
- if (dict_table_has_fts_index(ib_table)) {
-
- /* Check if table is in a consistent state.
- Crash during truncate can put table in an inconsistent state. */
- trx_t* trx = innobase_trx_allocate(ha_thd());
- bool sane = fts_is_corrupt(ib_table, trx);
- innobase_commit_low(trx);
- trx_free_for_mysql(trx);
- trx = NULL;
-
- if (!sane) {
- /* In-consistent fts index found. */
- free_share(m_share);
- set_my_errno(ENOENT);
-
- dict_table_close(ib_table, FALSE, FALSE);
- DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
- }
- }
-
if (!thd_tablespace_op(thd) && no_tablespace) {
free_share(m_share);
set_my_errno(ENOENT);
@@ -6931,29 +7171,35 @@ ha_innobase::open(
m_prebuilt->default_rec = table->s->default_values;
ut_ad(m_prebuilt->default_rec);
+ m_prebuilt->m_mysql_table = table;
+
/* Looks like MySQL-3.23 sometimes has primary key number != 0 */
m_primary_key = table->s->primary_key;
key_used_on_scan = m_primary_key;
+#ifdef MYSQL_VIRTUAL_COLUMNS
if (ib_table->n_v_cols) {
- if (!m_share->s_templ.vtempl) {
+ mutex_enter(&dict_sys->mutex);
+ if (ib_table->vc_templ == NULL) {
+ ib_table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
+ ib_table->vc_templ->vtempl = NULL;
+ } else if (ib_table->get_ref_count() == 1) {
+ /* Clean and refresh the template if no one else
+ get hold on it */
+ dict_free_vc_templ(ib_table->vc_templ);
+ ib_table->vc_templ->vtempl = NULL;
+ }
+
+ if (ib_table->vc_templ->vtempl == NULL) {
innobase_build_v_templ(
- table, ib_table, &(m_share->s_templ), NULL,
- false, m_share->table_name);
-
- mysql_mutex_lock(&innobase_share_mutex);
- if (ib_table->vc_templ
- && ib_table->vc_templ_purge) {
- free_vc_templ(ib_table->vc_templ);
- ut_free(ib_table->vc_templ);
- }
- mysql_mutex_unlock(&innobase_share_mutex);
+ table, ib_table, ib_table->vc_templ, NULL,
+ true, m_share->table_name);
}
- ib_table->vc_templ = &m_share->s_templ;
- } else {
- ib_table->vc_templ = NULL;
+
+ mutex_exit(&dict_sys->mutex);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
if (!innobase_build_index_translation(table, ib_table, m_share)) {
sql_print_error("Build InnoDB index translation table for"
@@ -7058,6 +7304,9 @@ ha_innobase::open(
/* Index block size in InnoDB: used by MySQL in query optimization */
stats.block_size = UNIV_PAGE_SIZE;
+ /* Init table lock structure */
+ thr_lock_data_init(&m_share->lock, &lock, NULL);
+
if (m_prebuilt->table != NULL) {
/* We update the highest file format in the system table
space, if this table has higher file format setting. */
@@ -7085,9 +7334,9 @@ ha_innobase::open(
dict_table_autoinc_unlock(m_prebuilt->table);
}
+#if MYSQL_PLUGIN_FULLTEXT_PARSER
/* Set plugin parser for fulltext index */
for (uint i = 0; i < table->s->keys; i++) {
- /* JAN: TODO: MySQL 5.7 FT Parser
if (table->key_info[i].flags & HA_USES_PARSER) {
dict_index_t* index = innobase_get_index(i);
plugin_ref parser = table->key_info[i].parser;
@@ -7105,47 +7354,37 @@ ha_innobase::open(
DBUG_EXECUTE_IF("fts_instrument_use_default_parser",
index->parser = &fts_default_parser;);
}
- */
}
+#endif
info(HA_STATUS_NO_LOCK | HA_STATUS_VARIABLE | HA_STATUS_CONST);
- /* We don't support compression for the system tablespace and
- the temporary tablespace. Only because they are shared tablespaces.
- There is no other technical reason. */
-
- if (m_prebuilt->table != NULL
- && !m_prebuilt->table->ibd_file_missing
- && !is_shared_tablespace(m_prebuilt->table->space)) {
-
- /* JAN: TODO: MySQL 5.7: Table options should be used here
- dberr_t err = fil_set_compression(
- m_prebuilt->table->space, table->s->compress.str);
- */
- dberr_t err = DB_SUCCESS;
+#ifdef MYSQL_COMPRESSION // MySQL 5.7 Compression
+ dberr_t err = fil_set_compression(m_prebuilt->table,
+ table->s->compress.str);
- switch (err) {
- case DB_NOT_FOUND:
- case DB_UNSUPPORTED:
- /* We will do another check before the create
- table and push the error to the client there. */
- break;
+ switch (err) {
+ case DB_NOT_FOUND:
+ case DB_UNSUPPORTED:
+ /* We will do another check before the create
+ table and push the error to the client there. */
+ break;
- case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
- /* We did the check in the 'if' above. */
+ case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
+ /* We did the check in the 'if' above. */
- case DB_IO_NO_PUNCH_HOLE_FS:
- /* During open we can't check whether the FS supports
- punch hole or not, at least on Linux. */
- break;
+ case DB_IO_NO_PUNCH_HOLE_FS:
+ /* During open we can't check whether the FS supports
+ punch hole or not, at least on Linux. */
+ break;
- default:
- ut_error;
+ default:
+ ut_error;
- case DB_SUCCESS:
- break;
- }
+ case DB_SUCCESS:
+ break;
}
+#endif
DBUG_RETURN(0);
}
@@ -7327,7 +7566,7 @@ get_field_offset(
UNIV_INTERN
int
wsrep_innobase_mysql_sort(
-/*===============*/
+/*======================*/
/* out: str contains sort string */
int mysql_type, /* in: MySQL type */
uint charset_number, /* in: number of the charset */
@@ -7384,8 +7623,8 @@ wsrep_innobase_mysql_sort(
memcpy(tmp_str, str, str_length);
tmp_length = charset->coll->strnxfrm(charset, str, str_length,
- str_length, tmp_str,
- tmp_length, 0);
+ str_length, tmp_str,
+ tmp_length, 0);
DBUG_ASSERT(tmp_length <= str_length);
if (wsrep_protocol_version < 3) {
tmp_length = charset->coll->strnxfrm(
@@ -7680,7 +7919,8 @@ get_innobase_type_from_mysql_type(
return(DATA_VARMYSQL);
}
case MYSQL_TYPE_BIT:
- case MYSQL_TYPE_STRING: if (field->binary()) {
+ case MYSQL_TYPE_STRING:
+ if (field->binary()) {
return(DATA_FIXBINARY);
} else if (strcmp(field->charset()->name,
@@ -7700,13 +7940,14 @@ get_innobase_type_from_mysql_type(
case MYSQL_TYPE_YEAR:
case MYSQL_TYPE_NEWDATE:
return(DATA_INT);
- case MYSQL_TYPE_TIMESTAMP:
case MYSQL_TYPE_TIME:
case MYSQL_TYPE_DATETIME:
- if (field->key_type() == HA_KEYTYPE_BINARY)
+ case MYSQL_TYPE_TIMESTAMP:
+ if (field->key_type() == HA_KEYTYPE_BINARY) {
return(DATA_FIXBINARY);
- else
+ } else {
return(DATA_INT);
+ }
case MYSQL_TYPE_FLOAT:
return(DATA_FLOAT);
case MYSQL_TYPE_DOUBLE:
@@ -7851,8 +8092,8 @@ wsrep_store_key_val_for_row(
true_len = (ulint) cs->cset->well_formed_len(cs,
(const char *) data,
(const char *) data + len,
- (uint) (key_len /
- cs->mbmaxlen),
+ (uint) (key_len /
+ cs->mbmaxlen),
&error);
}
@@ -7867,13 +8108,12 @@ wsrep_store_key_val_for_row(
true_len = wsrep_innobase_mysql_sort(
mysql_type, cs->number, sorted, true_len,
REC_VERSION_56_MAX_INDEX_COL_LEN);
-
if (wsrep_protocol_version > 1) {
- /* Note that we always reserve the maximum possible
- length of the true VARCHAR in the key value, though
- only len first bytes after the 2 length bytes contain
- actual data. The rest of the space was reset to zero
- in the bzero() call above. */
+ /* Note that we always reserve the maximum possible
+ length of the true VARCHAR in the key value, though
+ only len first bytes after the 2 length bytes contain
+ actual data. The rest of the space was reset to zero
+ in the bzero() call above. */
if (true_len > buff_space) {
fprintf (stderr,
"WSREP: key truncated: %s\n",
@@ -7881,11 +8121,11 @@ wsrep_store_key_val_for_row(
true_len = buff_space;
}
memcpy(buff, sorted, true_len);
- buff += true_len;
+ buff += true_len;
buff_space -= true_len;
- } else {
- buff += key_len;
- }
+ } else {
+ buff += key_len;
+ }
} else if (mysql_type == MYSQL_TYPE_TINY_BLOB
|| mysql_type == MYSQL_TYPE_MEDIUM_BLOB
|| mysql_type == MYSQL_TYPE_BLOB
@@ -7939,8 +8179,8 @@ wsrep_store_key_val_for_row(
(const char *) blob_data,
(const char *) blob_data
+ blob_len,
- (uint) (key_len /
- cs->mbmaxlen),
+ (uint) (key_len /
+ cs->mbmaxlen),
&error);
}
@@ -7960,7 +8200,7 @@ wsrep_store_key_val_for_row(
/* Note that we always reserve the maximum possible
length of the BLOB prefix in the key value. */
- if (wsrep_protocol_version > 1) {
+ if (wsrep_protocol_version > 1) {
if (true_len > buff_space) {
fprintf (stderr,
"WSREP: key truncated: %s\n",
@@ -8028,8 +8268,8 @@ wsrep_store_key_val_for_row(
(const char *)src_start,
(const char *)src_start
+ key_len,
- (uint) (key_len /
- cs->mbmaxlen),
+ (uint) (key_len /
+ cs->mbmaxlen),
&error);
}
memcpy(sorted, src_start, true_len);
@@ -8057,7 +8297,6 @@ wsrep_store_key_val_for_row(
DBUG_RETURN((uint)(buff - buff_start));
}
#endif /* WITH_WSREP */
-
/**************************************************************//**
Determines if a field is needed in a m_prebuilt struct 'template'.
@return field to use, or NULL if the field is not needed */
@@ -8083,7 +8322,7 @@ build_template_needs_field(
dict_index_t* index, /*!< in: InnoDB index to use */
const TABLE* table, /*!< in: MySQL table object */
ulint i, /*!< in: field index in InnoDB table */
- ulint sql_idx, /*!< in: field index in SQL table */
+ ulint sql_idx, /*!< in: field index in SQL table */
ulint num_v) /*!< in: num virtual column so far */
{
const Field* field = table->field[sql_idx];
@@ -8340,7 +8579,8 @@ ha_innobase::build_template(
/* Below we check column by column if we need to access
the clustered index. */
- n_stored_fields= (ulint)table->s->stored_fields; /* number of stored columns */
+ /* number of stored columns */
+ n_stored_fields= (ulint)table->s->stored_fields;
if (!m_prebuilt->mysql_template) {
m_prebuilt->mysql_template = (mysql_row_templ_t*)
@@ -8369,7 +8609,7 @@ ha_innobase::build_template(
for (i = 0, sql_idx = 0; i < n_stored_fields; i++, sql_idx++) {
ibool index_contains;
- while (!table->field[sql_idx]->stored_in_db()) {
+ while (!table->field[sql_idx]->stored_in_db()) {
sql_idx++;
}
@@ -8514,9 +8754,9 @@ ha_innobase::build_template(
mysql_row_templ_t* templ;
ibool index_contains;
- while (!table->field[sql_idx]->stored_in_db()) {
- sql_idx++;
- }
+ while (!table->field[sql_idx]->stored_in_db()) {
+ sql_idx++;
+ }
if (innobase_is_v_fld(table->field[sql_idx])) {
index_contains = dict_index_contains_col_or_prefix(
@@ -8571,9 +8811,9 @@ ha_innobase::build_template(
for (i = 0, sql_idx = 0; i < n_stored_fields; i++, sql_idx++) {
const Field* field;
- while (!table->field[sql_idx]->stored_in_db()) {
- sql_idx++;
- }
+ while (!table->field[sql_idx]->stored_in_db()) {
+ sql_idx++;
+ }
if (whole_row) {
/* Even this is whole_row, if the seach is
@@ -8587,13 +8827,13 @@ ha_innobase::build_template(
&& !dict_index_contains_col_or_prefix(
m_prebuilt->index, num_v, true))
{
- ut_ad(!bitmap_is_set(
- table->read_set, i));
- ut_ad(!bitmap_is_set(
- table->write_set, i));
-
+ /* Turn off ROW_MYSQL_WHOLE_ROW */
+ m_prebuilt->template_type =
+ ROW_MYSQL_REC_FIELDS;
+ num_v++;
continue;
}
+
field = table->field[sql_idx];
} else {
ibool contain;
@@ -8607,6 +8847,7 @@ ha_innobase::build_template(
false);
}
+
field = build_template_needs_field(
contain,
m_prebuilt->read_just_key,
@@ -8656,6 +8897,7 @@ dberr_t
ha_innobase::innobase_lock_autoinc(void)
/*====================================*/
{
+ DBUG_ENTER("ha_innobase::innobase_lock_autoinc");
dberr_t error = DB_SUCCESS;
long lock_mode = innobase_autoinc_lock_mode;
@@ -8702,6 +8944,8 @@ ha_innobase::innobase_lock_autoinc(void)
/* Fall through to old style locking. */
case AUTOINC_OLD_STYLE_LOCKING:
+ DBUG_EXECUTE_IF("die_if_autoinc_old_lock_style_used",
+ ut_ad(0););
error = row_lock_table_autoinc_for_mysql(m_prebuilt);
if (error == DB_SUCCESS) {
@@ -8715,7 +8959,7 @@ ha_innobase::innobase_lock_autoinc(void)
ut_error;
}
- return(error);
+ DBUG_RETURN(error);
}
/********************************************************************//**
@@ -8778,7 +9022,7 @@ ha_innobase::write_row(
{
dberr_t error;
#ifdef WITH_WSREP
- ibool auto_inc_inserted= FALSE; /* if NULL was inserted */
+ ibool auto_inc_inserted= FALSE; /* if NULL was inserted */
#endif
ulint sql_command;
int error_result = 0;
@@ -8796,7 +9040,10 @@ ha_innobase::write_row(
if (!dict_table_is_intrinsic(m_prebuilt->table)
&& trx_in_innodb.is_aborted()) {
- DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+ innobase_rollback(ht, m_user_thd, false);
+
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
/* Step-1: Validation checks before we commence write_row operation. */
@@ -9139,8 +9386,7 @@ report_error:
wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
wsrep_on(m_user_thd) &&
!wsrep_consistency_check(m_user_thd) &&
- !wsrep_thd_ignore_table(m_user_thd))
- {
+ !wsrep_thd_ignore_table(m_user_thd)) {
if (wsrep_append_keys(m_user_thd, false, record, NULL))
{
DBUG_PRINT("wsrep", ("row key failed"));
@@ -9240,7 +9486,7 @@ calc_row_difference(
uint sql_idx,i, innodb_idx= 0;
ibool changes_fts_column = FALSE;
ibool changes_fts_doc_col = FALSE;
- trx_t* trx = thd_to_trx(thd);
+ trx_t* trx = thd_to_trx(thd);
doc_id_t doc_id = FTS_NULL_DOC_ID;
ulint num_v = 0;
@@ -9342,12 +9588,34 @@ calc_row_difference(
}
}
+#ifdef UNIV_DEBUG
+ bool online_ord_part = false;
+#endif
+
if (is_virtual) {
/* If the virtual column is not indexed,
we shall ignore it for update */
if (!col->ord_part) {
- num_v++;
- continue;
+ /* Check whether there is a table-rebuilding
+ online ALTER TABLE in progress, and this
+ virtual column could be newly indexed, thus
+ it will be materialized. Then we will have
+ to log its update.
+ Note, we do not support online dropping virtual
+ column while adding new index, nor with
+ online alter column order while adding index,
+ so the virtual column sequence must not change
+ if it is online operation */
+ if (dict_index_is_online_ddl(clust_index)
+ && row_log_col_is_indexed(clust_index,
+ num_v)) {
+#ifdef UNIV_DEBUG
+ online_ord_part = true;
+#endif
+ } else {
+ num_v++;
+ continue;
+ }
}
if (!uvect->old_vrow) {
@@ -9423,7 +9691,7 @@ calc_row_difference(
upd_fld_set_virtual_col(ufield);
ufield->field_no = num_v;
- ut_ad(col->ord_part);
+ ut_ad(col->ord_part || online_ord_part);
ufield->old_v_val = static_cast<dfield_t*>(
mem_heap_alloc(
uvect->heap,
@@ -9500,12 +9768,12 @@ calc_row_difference(
prebuilt, vfield, o_len,
col, old_mysql_row_col,
col_pack_len, buf);
- ut_ad(col->ord_part);
+ ut_ad(col->ord_part || online_ord_part);
num_v++;
}
- if (field->stored_in_db()) {
- innodb_idx++;
+ if (field->stored_in_db()) {
+ innodb_idx++;
}
}
@@ -9584,7 +9852,7 @@ calc_row_difference(
ut_a(buf <= (byte*) original_upd_buff + buff_len);
- ut_ad(uvect->validate());
+ ut_ad(uvect->validate());
return(DB_SUCCESS);
}
@@ -9609,7 +9877,7 @@ wsrep_calc_row_hash(
uint i;
void *ctx = alloca(my_md5_context_size());
- my_md5_init(ctx);
+ my_md5_init(ctx);
n_fields = table->s->fields;
@@ -9670,6 +9938,7 @@ wsrep_calc_row_hash(
return(0);
}
#endif /* WITH_WSREP */
+
/*
Updates a row given as a parameter to a new value. Note that we are given
whole rows, not just the fields which are updated: this incurs some
@@ -9705,11 +9974,11 @@ ha_innobase::update_row(
if (m_upd_buf == NULL) {
ut_ad(m_upd_buf_size == 0);
- /* Create a buffer for packing the fields of a record. Why
- table->stored_rec_length did not work here? Obviously,
- because char fields when packed actually became 1 byte
- longer, when we also stored the string length as the first
- byte. */
+ /* Create a buffer for packing the fields of a record. Why
+ table->stored_rec_length did not work here? Obviously,
+ because char fields when packed actually became 1 byte
+ longer, when we also stored the string length as the first
+ byte. */
m_upd_buf_size = table->s->stored_rec_length + table->s->max_key_length
+ MAX_REF_PARTS * 3;
@@ -9750,7 +10019,10 @@ ha_innobase::update_row(
if (!dict_table_is_intrinsic(m_prebuilt->table)
&& TrxInInnoDB::is_aborted(trx)) {
- DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+ innobase_rollback(ht, m_user_thd, false);
+
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
/* This is not a delete */
@@ -9830,8 +10102,7 @@ func_exit:
if (error == DB_SUCCESS &&
wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
wsrep_on(m_user_thd) &&
- !wsrep_thd_ignore_table(m_user_thd))
- {
+ !wsrep_thd_ignore_table(m_user_thd)) {
DBUG_PRINT("wsrep", ("update row key"));
if (wsrep_append_keys(m_user_thd, false, old_row, new_row)) {
@@ -9866,7 +10137,10 @@ ha_innobase::delete_row(
if (!dict_table_is_intrinsic(m_prebuilt->table)
&& trx_in_innodb.is_aborted()) {
- DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+ innobase_rollback(ht, m_user_thd, false);
+
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
ut_a(m_prebuilt->trx == trx);
@@ -9901,10 +10175,9 @@ ha_innobase::delete_row(
#ifdef WITH_WSREP
if (error == DB_SUCCESS &&
- wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
- wsrep_on(m_user_thd) &&
- !wsrep_thd_ignore_table(m_user_thd))
- {
+ wsrep_thd_exec_mode(m_user_thd) == LOCAL_STATE &&
+ wsrep_on(m_user_thd) &&
+ !wsrep_thd_ignore_table(m_user_thd)) {
if (wsrep_append_keys(m_user_thd, false, record, NULL)) {
DBUG_PRINT("wsrep", ("delete fail"));
error = (dberr_t) HA_ERR_INTERNAL_ERROR;
@@ -10106,8 +10379,8 @@ convert_search_mode_to_innobase(
return(PAGE_CUR_MBR_EQUAL);
case HA_READ_PREFIX:
return(PAGE_CUR_UNSUPP);
- /* JAN: TODO: MySQL 5.7
- case HA_READ_INVALID:
+ /* JAN: TODO: MySQL 5.7
+ case HA_READ_INVALID:
return(PAGE_CUR_UNSUPP);
*/
/* do not use "default:" in order to produce a gcc warning:
@@ -10275,8 +10548,10 @@ ha_innobase::index_read(
if (TrxInInnoDB::is_aborted(m_prebuilt->trx)) {
- DBUG_RETURN(innobase_rollback(
- ht, m_user_thd, false));
+ innobase_rollback(ht, m_user_thd, false);
+
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
m_prebuilt->ins_sel_stmt = thd_is_ins_sel_stmt(
@@ -10401,7 +10676,7 @@ ha_innobase::innobase_get_index(
if (!key || ut_strcmp(index->name, key->name) != 0) {
ib::error() << " Index for key no " << keynr
<< " mysql name " << (key ? key->name : "NULL")
- << " InnoDB name " << index->name
+ << " InnoDB name " << index->name()
<< " for table " << m_prebuilt->table->name.m_name;
for(ulint i=0; i < table->s->keys; i++) {
@@ -10411,7 +10686,7 @@ ha_innobase::innobase_get_index(
if (index) {
ib::info() << " Index for key no " << keynr
<< " mysql name " << (key ? key->name : "NULL")
- << " InnoDB name " << index->name
+ << " InnoDB name " << index->name()
<< " for table " << m_prebuilt->table->name.m_name;
}
}
@@ -10430,7 +10705,8 @@ ha_innobase::innobase_get_index(
" index translation table",
key ? key->name : "NULL",
keynr,
- m_prebuilt->table->name.m_name);
+ m_prebuilt->table->name
+ .m_name);
}
index = dict_table_get_index_on_name(
@@ -10473,7 +10749,10 @@ ha_innobase::change_active_index(
if (!dict_table_is_intrinsic(m_prebuilt->table)
&& trx_in_innodb.is_aborted()) {
- DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+ innobase_rollback(ht, m_user_thd, false);
+
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
active_index = keynr;
@@ -10527,7 +10806,7 @@ ha_innobase::change_active_index(
/* The caller seems to ignore this. Thus, we must check
this again in row_search_for_mysql(). */
DBUG_RETURN(convert_error_code_to_mysql(DB_MISSING_HISTORY,
- 0, NULL));
+ 0, NULL));
}
ut_a(m_prebuilt->search_tuple != 0);
@@ -10536,14 +10815,14 @@ ha_innobase::change_active_index(
since FT search returns rank only. In addition engine should
be able to retrieve FTS_DOC_ID column value if necessary. */
if ((m_prebuilt->index->type & DICT_FTS)) {
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_STORE_FTS_DOC_ID
if (table->fts_doc_id_field
&& bitmap_is_set(table->read_set,
table->fts_doc_id_field->field_index
&& m_prebuilt->read_just_key)) {
m_prebuilt->fts_doc_id_in_read_set = 1;
}
- */
+#endif
} else {
dtuple_set_n_fields(m_prebuilt->search_tuple,
m_prebuilt->index->n_fields);
@@ -10554,11 +10833,13 @@ ha_innobase::change_active_index(
/* If it's FTS query and FTS_DOC_ID exists FTS_DOC_ID field is
always added to read_set. */
- /* JAN: TODO: MySQL 5.7
+
+#ifdef MYSQL_STORE_FTS_DOC_ID
m_prebuilt->fts_doc_id_in_read_set =
(m_prebuilt->read_just_key && table->fts_doc_id_field
&& m_prebuilt->in_fts_query);
- */
+#endif
+
}
/* MySQL changes the active index for a handle also during some
@@ -10589,6 +10870,7 @@ ha_innobase::general_fetch(
DBUG_ENTER("general_fetch");
const trx_t* trx = m_prebuilt->trx;
+ dberr_t ret;
ut_ad(trx == thd_to_trx(m_user_thd));
@@ -10596,17 +10878,20 @@ ha_innobase::general_fetch(
if (!intrinsic && TrxInInnoDB::is_aborted(trx)) {
- DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+ innobase_rollback(ht, m_user_thd, false);
+
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
innobase_srv_conc_enter_innodb(m_prebuilt);
- dberr_t ret;
-
if (!intrinsic) {
+
ret = row_search_mvcc(
buf, PAGE_CUR_UNSUPP, m_prebuilt, match_mode,
direction);
+
} else {
ret = row_search_no_mvcc(
buf, PAGE_CUR_UNSUPP, m_prebuilt, match_mode,
@@ -10654,9 +10939,7 @@ ha_innobase::general_fetch(
table->s->table_name.str);
table->status = STATUS_NOT_FOUND;
- error = HA_ERR_NO_SUCH_TABLE;
- // JAN: TODO: MySQL 5.7
- //error = HA_ERR_TABLESPACE_MISSING;
+ error = HA_ERR_TABLESPACE_MISSING;
break;
default:
error = convert_error_code_to_mysql(
@@ -10963,9 +11246,13 @@ ha_innobase::ft_init_ext(
if (trx_in_innodb.is_aborted()) {
- int ret = innobase_rollback(ht, m_user_thd, false);
+ innobase_rollback(ht, m_user_thd, false);
- my_error(ret, MYF(0));
+ int err;
+ err = convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd);
+
+ my_error(err, MYF(0));
return(NULL);
}
@@ -11016,7 +11303,8 @@ ha_innobase::ft_init_ext(
const byte* q = reinterpret_cast<const byte*>(
const_cast<char*>(query));
- dberr_t error = fts_query(trx, index, flags, q, query_len, &result);
+ dberr_t error = fts_query(trx, index, flags, q, query_len, &result,
+ m_prebuilt->m_fts_limit);
if (error != DB_SUCCESS) {
my_error(convert_error_code_to_mysql(error, 0, NULL), MYF(0));
@@ -11050,13 +11338,14 @@ ha_innobase::ft_init_ext_with_hints(
/*================================*/
uint keynr, /* in: key num */
String* key, /* in: key */
- void* hints) /* in: hints */
-// JAN: TODO: MySQL 5.7
-// Ft_hints* hints) /* in: hints */
+ void* hints) /* in: hints */
{
/* TODO Implement function properly working with FT hint. */
- //return(ft_init_ext(hints->get_flags(), keynr, key));
+#ifdef MYSQL_FT_INIT_EXT
+ return(ft_init_ext(hints->get_flags(), keynr, key));
+#else
return NULL;
+#endif
}
/*****************************************************************//**
@@ -11116,7 +11405,10 @@ ha_innobase::ft_read(
if (trx_in_innodb.is_aborted()) {
- return(innobase_rollback(ht, m_user_thd, false));
+ innobase_rollback(ht, m_user_thd, false);
+
+ return(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
row_prebuilt_t* ft_prebuilt;
@@ -11158,6 +11450,7 @@ next_record:
/* If we only need information from result we can return
without fetching the table row */
if (ft_prebuilt->read_just_key) {
+#ifdef MYSQL_STORE_FTS_DOC_ID
if (m_prebuilt->fts_doc_id_in_read_set) {
fts_ranking_t* ranking;
ranking = rbt_value(fts_ranking_t,
@@ -11165,6 +11458,7 @@ next_record:
innobase_fts_store_docid(
table, ranking->doc_id);
}
+#endif
table->status= 0;
return(0);
}
@@ -11241,9 +11535,7 @@ next_record:
table->s->table_name.str);
table->status = STATUS_NOT_FOUND;
- error = HA_ERR_NO_SUCH_TABLE;
- // JAN: TODO: MySQL 5.7
- // error = HA_ERR_TABLESPACE_MISSING;
+ error = HA_ERR_TABLESPACE_MISSING;
break;
default:
error = convert_error_code_to_mysql(
@@ -11391,8 +11683,9 @@ wsrep_append_foreign_key(
WSREP_ERROR(
"FK key set failed: %lu (%lu %lu), index: %s %s, %s",
rcode, referenced, shared,
- (index) ? index->name() : "void index",
- (index) ? index->table->name.m_name : "void table",
+ (index) ? index->name() : "void index",
+ (index && index->table) ? index->table->name.m_name :
+ "void table",
wsrep_thd_query(thd));
return DB_ERROR;
}
@@ -11802,6 +12095,7 @@ create_table_check_doc_id_col(
return(false);
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
/** Set up base columns for virtual column
@param[in] table InnoDB table
@param[in] field MySQL field
@@ -11812,9 +12106,10 @@ innodb_base_col_setup(
const Field* field,
dict_v_col_t* v_col)
{
+ int n = 0;
+
for (uint i= 0; i < field->table->s->fields; ++i) {
- // const Field* base_field = field->table->field[i];
- /* JAN: TODO: MySQL 5.7 Virtual columns
+ const Field* base_field = field->table->field[i];
if (!base_field->is_virtual_gcol()
&& bitmap_is_set(&field->gcol_info->base_columns_map, i)) {
ulint z;
@@ -11833,19 +12128,62 @@ innodb_base_col_setup(
ut_ad(v_col->base_col[n]->ind == z);
n++;
}
- */
}
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
+#ifdef MYSQL_BASE_COLUMN
+/** Set up base columns for stored column
+@param[in] table InnoDB table
+@param[in] field MySQL field
+@param[in,out] s_col stored column */
+void
+innodb_base_col_setup_for_stored(
+ const dict_table_t* table,
+ const Field* field,
+ dict_s_col_t* s_col)
+{
+ ulint n = 0;
+
+ for (uint i= 0; i < field->table->s->fields; ++i) {
+ const Field* base_field = field->table->field[i];
+
+ if (!innobase_is_s_fld(base_field)
+ && !innobase_is_v_fld(base_field)
+ && bitmap_is_set(&field->gcol_info->base_columns_map,
+ i)) {
+ ulint z;
+ for (z = 0; z < table->n_cols; z++) {
+ const char* name = dict_table_get_col_name(
+ table, z);
+ if (!innobase_strcasecmp(
+ name, base_field->field_name)) {
+ break;
+ }
+ }
+
+ ut_ad(z != table->n_cols);
+
+ s_col->base_col[n] = dict_table_get_nth_col(table, z);
+ n++;
+
+ if (n == s_col->num_base) {
+ break;
+ }
+ }
+ }
+}
+#endif
/** Create a table definition to an InnoDB database.
@return ER_* level error */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
int
create_table_info_t::create_table_def()
{
dict_table_t* table;
ulint n_cols;
- dberr_t err;
+ ulint s_cols;
ulint col_type;
ulint col_len;
ulint nulls_allowed;
@@ -11862,6 +12200,7 @@ create_table_info_t::create_table_def()
ulint space_id = 0;
ulint actual_n_cols;
ha_table_option_struct *options= m_form->s->option_struct;
+ dberr_t err = DB_SUCCESS;
DBUG_ENTER("create_table_def");
DBUG_PRINT("enter", ("table_name: %s", m_table_name));
@@ -11890,7 +12229,9 @@ create_table_info_t::create_table_def()
}
n_cols = m_form->s->fields;
+ s_cols = m_form->s->stored_fields;
+#ifdef MYSQL_VIRTUAL_COLUMNS
/* Find out any virtual column */
for (i = 0; i < n_cols; i++) {
Field* field = m_form->field[i];
@@ -11899,13 +12240,15 @@ create_table_info_t::create_table_def()
num_v++;
}
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
+ ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED));
/* Check whether there already exists a FTS_DOC_ID column */
if (create_table_check_doc_id_col(m_trx, m_form, &doc_id_col)){
/* Raise error if the Doc ID column is of wrong type or name */
if (doc_id_col == ULINT_UNDEFINED) {
- trx_commit_for_mysql(m_trx);
err = DB_ERROR;
goto error_ret;
@@ -11935,7 +12278,7 @@ create_table_info_t::create_table_def()
/* Set the hidden doc_id column. */
if (m_flags2 & DICT_TF2_FTS) {
table->fts->doc_col = has_doc_id_col
- ? doc_id_col : n_cols - num_v;
+ ? doc_id_col : s_cols;
}
if (strlen(m_temp_path) != 0) {
@@ -11964,9 +12307,10 @@ create_table_info_t::create_table_def()
for (i = 0; i < n_cols; i++) {
ulint is_virtual;
+ bool is_stored MY_ATTRIBUTE((unused));
Field* field = m_form->field[i];
- if (!field->stored_in_db()) {
+ if (!field->stored_in_db()) {
continue;
}
@@ -12014,6 +12358,10 @@ create_table_info_t::create_table_def()
charset_no = (ulint) field->charset()->number;
+ DBUG_EXECUTE_IF("simulate_max_char_col",
+ charset_no = MAX_CHAR_COLL_NUM + 1;
+ );
+
if (charset_no > MAX_CHAR_COLL_NUM) {
/* in data0type.h we assume that the
number fits in one byte in prtype */
@@ -12025,6 +12373,11 @@ create_table_info_t::create_table_def()
" Unsupported code %lu.",
(ulong) charset_no);
mem_heap_free(heap);
+ dict_mem_table_free(table);
+
+ ut_ad(trx_state_eq(
+ m_trx, TRX_STATE_NOT_STARTED));
+
DBUG_RETURN(ER_CANT_CREATE_TABLE);
}
}
@@ -12051,6 +12404,7 @@ create_table_info_t::create_table_def()
}
is_virtual = (innobase_is_v_fld(field)) ? DATA_VIRTUAL : 0;
+ is_stored = innobase_is_s_fld(field);
/* First check whether the column to be added has a
system reserved name. */
@@ -12060,7 +12414,7 @@ create_table_info_t::create_table_def()
err_col:
dict_mem_table_free(table);
mem_heap_free(heap);
- trx_commit_for_mysql(m_trx);
+ ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED));
err = DB_ERROR;
goto error_ret;
@@ -12076,6 +12430,7 @@ err_col:
charset_no),
col_len);
} else {
+#ifdef MYSQL_VIRTUAL_COLUMNS
dict_mem_table_add_v_col(table, heap,
field_name, col_type,
dtype_form_prtype(
@@ -12086,11 +12441,22 @@ err_col:
charset_no),
col_len, i,
0);
- // JAN: TODO: MySQL 5.7 Virtual columns
- //field->gcol_info->non_virtual_base_columns());
- }
+
+ field->gcol_info->non_virtual_base_columns());
+#endif
}
+#ifdef MYSQL_STORED_BASE_COLUMNS
+ if (is_stored) {
+ ut_ad(!is_virtual);
+ /* Added stored column in m_s_cols list. */
+ dict_mem_table_add_s_col(
+ table,
+ field->gcol_info->non_virtual_base_columns());
+ }
+#endif
+ }
+#ifdef MYSQL_VIRTUAL_COLUMNS
if (num_v) {
for (i = 0; i < n_cols; i++) {
dict_v_col_t* v_col;
@@ -12109,22 +12475,45 @@ err_col:
}
}
+ /** Fill base columns for the stored column present in the list. */
+ if (table->s_cols && table->s_cols->size()) {
+
+ for (i = 0; i < n_cols; i++) {
+ Field* field = m_form->field[i];
+
+ if (!innobase_is_s_fld(field)) {
+ continue;
+ }
+
+ dict_s_col_list::iterator it;
+ for (it = table->s_cols->begin();
+ it != table->s_cols->end(); ++it) {
+ dict_s_col_t s_col = *it;
+
+ if (s_col.s_pos == i) {
+ innodb_base_col_setup_for_stored(
+ table, field, &s_col);
+ break;
+ }
+ }
+ }
+ }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
/* Add the FTS doc_id hidden column. */
if (m_flags2 & DICT_TF2_FTS && !has_doc_id_col) {
fts_add_doc_id_column(table, heap);
}
+ ut_ad(trx_state_eq(m_trx, TRX_STATE_NOT_STARTED));
+
/* If temp table, then we avoid creation of entries in SYSTEM TABLES.
Given that temp table lifetime is limited to connection/server lifetime
on re-start we don't need to restore temp-table and so no entry is
needed in SYSTEM tables. */
if (dict_table_is_temporary(table)) {
- ulint clen = 0;
-
- // JAN: TODO: MySQL 5.7 compressed tables
- // if (m_create_info->compress.length > 0) {
-
- if (clen > 0) {
+#ifdef MYSQL_COMPRESSION
+ if (m_create_info->compress.length > 0) {
push_warning_printf(
m_thd,
Sql_condition::WARN_LEVEL_WARN,
@@ -12134,8 +12523,17 @@ err_col:
err = DB_UNSUPPORTED;
- } else {
+ dict_mem_table_free(table);
+ } else if (m_create_info->encrypt_type.length > 0
+ && !Encryption::is_none(
+ m_create_info->encrypt_type.str)) {
+ my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0));
+ err = DB_UNSUPPORTED;
+ dict_mem_table_free(table);
+ */
+ } else {
+#endif /* MYSQL_COMPRESSION */
/* Get a new table ID */
dict_table_assign_new_id(table, m_trx);
@@ -12167,22 +12565,18 @@ err_col:
mem_heap_free(temp_table_heap);
}
+#ifdef MYSQL_COMPRESSION
}
+#endif
} else {
+ const char* algorithm = NULL;
- const char* algorithm = "";
- // JAN: TODO: MySQL 5.7
- // const char* algorithm = m_create_info->compress.str;
-
- err = DB_SUCCESS;
- ulint clen = 0;
+#if MYSQL_COMPRESSION_ENCRYPTION
+ const char* algorithm = m_create_info->compress.str;
- // if (!(m_flags2 & DICT_TF2_USE_FILE_PER_TABLE)
- // && m_create_info->compress.length > 0
- // && !Compression::is_none(algorithm)) {
if (!(m_flags2 & DICT_TF2_USE_FILE_PER_TABLE)
- && clen > 0
+ && m_create_info->compress.length > 0
&& !Compression::is_none(algorithm)) {
push_warning_printf(
@@ -12195,24 +12589,60 @@ err_col:
algorithm = NULL;
err = DB_UNSUPPORTED;
+ dict_mem_table_free(table);
} else if (Compression::validate(algorithm) != DB_SUCCESS
|| m_form->s->row_type == ROW_TYPE_COMPRESSED
|| m_create_info->key_block_size > 0) {
algorithm = NULL;
- }
+ }
+
+ const char* encrypt = m_create_info->encrypt_type.str;
+
+ if (!(m_flags2 & DICT_TF2_USE_FILE_PER_TABLE)
+ && m_create_info->encrypt_type.length > 0
+ && !Encryption::is_none(encrypt)) {
+
+ my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0));
+ err = DB_UNSUPPORTED;
+ dict_mem_table_free(table);
+
+ } else if (!Encryption::is_none(encrypt)) {
+ /* Set the encryption flag. */
+ byte* master_key = NULL;
+ ulint master_key_id;
+ Encryption::Version version;
+
+ /* Check if keyring is ready. */
+ Encryption::get_master_key(&master_key_id,
+ &master_key,
+ &version);
+
+ if (master_key == NULL) {
+ my_error(ER_CANNOT_FIND_KEY_IN_KEYRING,
+ MYF(0));
+ err = DB_UNSUPPORTED;
+ dict_mem_table_free(table);
+ } else {
+ my_free(master_key);
+ DICT_TF2_FLAG_SET(table,
+ DICT_TF2_ENCRYPTION);
+ }
+ }
+#endif /* MYSQL_COMPRESSION_ENCRYPTION */
if (err == DB_SUCCESS) {
err = row_create_table_for_mysql(
table, algorithm, m_trx, false,
(fil_encryption_t)options->encryption,
options->encryption_key_id);
+
}
if (err == DB_IO_NO_PUNCH_HOLE_FS) {
- ut_ad(!is_shared_tablespace(table->space));
+ ut_ad(!dict_table_in_shared_tablespace(table));
push_warning_printf(
m_thd,
@@ -12224,6 +12654,9 @@ err_col:
err = DB_SUCCESS;
}
+
+ DBUG_EXECUTE_IF("ib_crash_during_create_for_encryption",
+ DBUG_SUICIDE(););
}
mem_heap_free(heap);
@@ -12328,6 +12761,7 @@ create_index(
key->user_defined_key_parts * sizeof *
field_lengths, MYF(MY_FAE));
*/
+
field_lengths = (ulint*) my_malloc(
key->user_defined_key_parts * sizeof *
field_lengths, MYF(MY_FAE));
@@ -12628,7 +13062,9 @@ validate_tablespace_name(
bool
create_table_info_t::create_option_tablespace_is_valid()
{
- ut_ad(m_use_shared_space);
+ if (!m_use_shared_space) {
+ return(true);
+ }
if (0 != validate_tablespace_name(m_create_info->tablespace, true)) {
return(false);
@@ -12747,6 +13183,77 @@ create_table_info_t::create_option_tablespace_is_valid()
return(true);
}
+#ifdef MYSQL_COMPRESSION
+/** Validate the COPMRESSION option.
+@return true if valid, false if not. */
+bool
+create_table_info_t::create_option_compression_is_valid()
+{
+ dberr_t err;
+ Compression compression;
+
+ if (m_create_info->compress.length == 0) {
+ return(true);
+ }
+
+ err = Compression::check(m_create_info->compress.str, &compression);
+
+ if (err == DB_UNSUPPORTED) {
+ push_warning_printf(
+ m_thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ ER_UNSUPPORTED_EXTENSION,
+ "InnoDB: Unsupported compression algorithm '%s'",
+ m_create_info->compress.str);
+ return(false);
+ }
+
+ /* Allow Compression=NONE on any tablespace or row format. */
+ if (compression.m_type == Compression::NONE) {
+ return(true);
+ }
+
+ static char intro[] = "InnoDB: Page Compression is not supported";
+
+ if (m_create_info->key_block_size != 0
+ || m_create_info->row_type == ROW_TYPE_COMPRESSED) {
+ push_warning_printf(
+ m_thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_UNSUPPORTED_EXTENSION,
+ "%s with row_format=compressed or"
+ " key_block_size > 0", intro);
+ return(false);
+ }
+
+ if (m_create_info->options & HA_LEX_CREATE_TMP_TABLE) {
+ push_warning_printf(
+ m_thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_UNSUPPORTED,
+ "%s for temporary tables", intro);
+ return(false);
+ }
+
+ if (tablespace_is_general_space(m_create_info)) {
+ push_warning_printf(
+ m_thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_UNSUPPORTED,
+ "%s for shared general tablespaces", intro);
+ return(false);
+ }
+
+ /* The only non-file-per-table tablespace left is the system space. */
+ if (!m_use_file_per_table) {
+ push_warning_printf(
+ m_thd, Sql_condition::WARN_LEVEL_WARN,
+ HA_ERR_UNSUPPORTED,
+ "%s for the system tablespace", intro);
+ return(false);
+ }
+
+ return(true);
+}
+#endif /* MYSQL_COMPRESSION */
+
/** Validate the create options. Check that the options KEY_BLOCK_SIZE,
ROW_FORMAT, DATA DIRECTORY, TEMPORARY & TABLESPACE are compatible with
each other and other settings. These CREATE OPTIONS are not validated
@@ -12769,17 +13276,18 @@ create_table_info_t::create_options_are_invalid()
non-strict-mode. If it is incorrect or is incompatible with other
options, then we will return an error. Make sure the tablespace exists
and is compatible with this table */
- if (m_use_shared_space
- && !create_option_tablespace_is_valid()) {
+ if (!create_option_tablespace_is_valid()) {
return("TABLESPACE");
}
- /* If innodb_strict_mode is not set don't do any more validation. */
+ /* If innodb_strict_mode is not set don't do any more validation.
+ Also, if this table is being put into a shared general tablespace
+ we ALWAYS act like strict mode is ON. */
if (!m_use_shared_space && !(THDVAR(m_thd, strict_mode))) {
return(NULL);
}
- /* First check if a non-zero KEY_BLOCK_SIZE was specified. */
+ /* Check if a non-zero KEY_BLOCK_SIZE was specified. */
if (has_key_block_size) {
switch (m_create_info->key_block_size) {
ulint kbs_max;
@@ -12943,44 +13451,24 @@ create_table_info_t::create_options_are_invalid()
}
}
-#ifdef MYSQL_COMPRESSION
- /* Note: Currently the max length is 4: ZLIB, LZ4, NONE. */
-
- if (ret == NULL && m_create_info->compress.length > 0) {
+#ifdef MYSQL_COMPRESSION_ENCRYPTION
+ /* Validate the page compression parameter. */
+ if (!create_option_compression_is_valid()) {
+ return("COMPRESSION");
+ }
+ /* Check the encryption option. */
+ if (ret == NULL && m_create_info->encrypt_type.length > 0) {
dberr_t err;
- Compression compression;
- err = Compression::check(
- m_create_info->compress.str, &compression);
+ err = Encryption::validate(m_create_info->encrypt_type.str);
if (err == DB_UNSUPPORTED) {
-
- push_warning_printf(
- m_thd,
- Sql_condition::WARN_LEVEL_WARN,
- ER_UNSUPPORTED_EXTENSION,
- "InnoDB: Unsupported compression algorithm '"
- "%s'",
- m_create_info->compress.str);
-
- ret = "COMPRESSION";
-
- } else if (m_create_info->key_block_size > 0
- && compression.m_type != Compression::NONE) {
-
- push_warning_printf(
- m_thd,
- Sql_condition::WARN_LEVEL_WARN,
- ER_UNSUPPORTED_EXTENSION,
- "InnODB: Attribute not supported with row "
- "format compressed or key block size > 0");
-
- ret = "COMPRESSION";
+ my_error(ER_INVALID_ENCRYPTION_OPTION, MYF(0));
+ ret = "ENCRYPTION";
}
-
}
-#endif /* MYSQL_COMPRESSION */
+#endif
return(ret);
}
@@ -12988,7 +13476,6 @@ create_table_info_t::create_options_are_invalid()
/*****************************************************************//**
Check engine specific table options not handled by SQL-parser.
@return NULL if valid, string if not */
-UNIV_INTERN
const char*
create_table_info_t::check_table_options()
{
@@ -13005,7 +13492,7 @@ create_table_info_t::check_table_options()
return "ENCRYPTED";
}
- if (encrypt == FIL_SPACE_ENCRYPTION_OFF && srv_encrypt_tables == 2) {
+ if (encrypt == FIL_SPACE_ENCRYPTION_OFF && srv_encrypt_tables == 2) {
push_warning(
m_thd, Sql_condition::WARN_LEVEL_WARN,
HA_WRONG_CREATE_OPTION,
@@ -13087,7 +13574,7 @@ create_table_info_t::check_table_options()
/* If encryption is set up make sure that used key_id is found */
if (encrypt == FIL_SPACE_ENCRYPTION_ON ||
- (encrypt == FIL_SPACE_ENCRYPTION_DEFAULT && srv_encrypt_tables)) {
+ (encrypt == FIL_SPACE_ENCRYPTION_DEFAULT && srv_encrypt_tables)) {
if (!encryption_key_id_exists((unsigned int)options->encryption_key_id)) {
push_warning_printf(
m_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -13312,6 +13799,40 @@ create_table_info_t::innobase_table_flags()
m_flags = 0;
m_flags2 = 0;
+#ifdef MYSQL_COMPRESSION
+ /* Validate the page compression parameter. */
+ if (!create_option_compression_is_valid()) {
+ /* No need to do anything. Warnings were issued.
+ The compresion setting will be ignored later.
+ If inodb_strict_mode=ON, this is called twice unless
+ there was a problem before.
+ If inodb_strict_mode=OFF, this is the only call. */
+ }
+#endif
+
+#ifdef MYSQL_ENCRYPTION
+ /* Validate the page encryption parameter. */
+ if (m_create_info->encrypt_type.length > 0) {
+
+ const char* encryption = m_create_info->encrypt_type.str;
+
+ if (Encryption::validate(encryption) != DB_SUCCESS) {
+ /* Incorrect encryption option */
+ my_error(ER_INVALID_ENCRYPTION_OPTION, MYF(0));
+ DBUG_RETURN(false);
+ }
+
+ if (m_use_shared_space
+ || (m_create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
+ if (!Encryption::is_none(encryption)) {
+ /* Can't encrypt shared tablespace */
+ my_error(ER_TABLESPACE_CANNOT_ENCRYPT, MYF(0));
+ DBUG_RETURN(false);
+ }
+ }
+ }
+#endif /* MYSQL_ENCRYPTION */
+
/* Check if there are any FTS indexes defined on this table. */
for (uint i = 0; i < m_form->s->keys; i++) {
const KEY* key = &m_form->key_info[i];
@@ -13327,11 +13848,6 @@ create_table_info_t::innobase_table_flags()
DBUG_RETURN(false);
}
- if (key->flags & HA_USES_PARSER) {
- my_error(ER_INNODB_NO_FT_USES_PARSER, MYF(0));
- DBUG_RETURN(false);
- }
-
if (fts_doc_id_index_bad) {
goto index_bad;
}
@@ -13368,7 +13884,6 @@ index_bad:
}
//rec_format_t row_format = m_form->s->row_type;
- ulint clen = 0;
if (m_create_info->key_block_size > 0) {
/* The requested compressed page size (key_block_size)
@@ -13414,35 +13929,6 @@ index_bad:
"InnoDB: ignoring KEY_BLOCK_SIZE=%lu.",
m_create_info->key_block_size);
}
-
- } else if (clen > 0) {
- // JAN: TODO: MySQL 5.7
- //} else if (m_create_info->compress.length > 0) {
-
- if (m_use_shared_space
- || (m_create_info->options & HA_LEX_CREATE_TMP_TABLE)) {
-
- push_warning_printf(
- m_thd,
- Sql_condition::WARN_LEVEL_WARN,
- HA_ERR_UNSUPPORTED,
- "InnoDB: Cannot compress pages of shared "
- "tablespaces");
- }
-
- //const char* compression = m_create_info->compress.str;
- const char* compression = "";
-
- if (Compression::validate(compression) != DB_SUCCESS) {
-
- push_warning_printf(
- m_thd,
- Sql_condition::WARN_LEVEL_WARN,
- HA_ERR_UNSUPPORTED,
- "InnoDB: Unsupported compression "
- "algorithm '%s'",
- compression);
- }
}
row_type = m_form->s->row_type;
@@ -13507,15 +13993,15 @@ index_bad:
} else {
switch(row_type) {
- case ROW_TYPE_COMPRESSED:
- innodb_row_format = REC_FORMAT_COMPRESSED;
- break;
- case ROW_TYPE_DYNAMIC:
- innodb_row_format = REC_FORMAT_DYNAMIC;
- break;
- default:
- /* Not possible, avoid compiler warning */
- break;
+ case ROW_TYPE_COMPRESSED:
+ innodb_row_format = REC_FORMAT_COMPRESSED;
+ break;
+ case ROW_TYPE_DYNAMIC:
+ innodb_row_format = REC_FORMAT_DYNAMIC;
+ break;
+ default:
+ /* Not possible, avoid compiler warning */
+ break;
}
break; /* Correct row_format */
}
@@ -13554,19 +14040,20 @@ index_bad:
m_flags2 |= DICT_TF2_TEMPORARY;
/* Intrinsic tables reside only in the shared temporary
tablespace and we will always use ROW_FORMAT=DYNAMIC. */
- /* JAN: TODO: MySQL 5.7
+
+#ifdef MYSQL_COMPRESSION
if ((m_create_info->options & HA_LEX_CREATE_INTERNAL_TMP_TABLE)
&& !m_use_file_per_table) {
- if (!m_use_file_per_table) {
- */
+
/* We do not allow compressed instrinsic
temporary tables. */
- /*
+
ut_ad(zip_ssize == 0);
m_flags2 |= DICT_TF2_INTRINSIC;
innodb_row_format = REC_FORMAT_DYNAMIC;
}
- */
+#endif
+
}
/* Set the table flags */
@@ -13818,8 +14305,6 @@ create_table_info_t::initialize()
DBUG_RETURN(HA_ERR_TOO_MANY_FIELDS);
}
- ut_ad(m_form->s->row_type == m_create_info->row_type);
-
/* Check for name conflicts (with reserved name) for
any user indices to be created. */
if (innobase_index_name_is_reserved(m_thd, m_form->key_info,
@@ -13827,6 +14312,8 @@ create_table_info_t::initialize()
DBUG_RETURN(HA_ERR_WRONG_INDEX);
}
+ ut_ad(m_form->s->row_type == m_create_info->row_type);
+
/* Get the transaction associated with the current thd, or create one
if not yet created */
@@ -13839,6 +14326,7 @@ create_table_info_t::initialize()
DBUG_RETURN(0);
}
+
/** Prepare to create a new table to an InnoDB database.
@param[in] name Table name
@return error number */
@@ -13858,7 +14346,7 @@ create_table_info_t::prepare_create_table(
normalize_table_name(m_table_name, name);
/* Validate table options not handled by the SQL-parser */
- if(check_table_options()) {
+ if (check_table_options()) {
DBUG_RETURN(HA_WRONG_CREATE_OPTION);
}
@@ -13877,9 +14365,7 @@ create_table_info_t::prepare_create_table(
}
if (high_level_read_only && !is_intrinsic_temp_table()) {
- DBUG_RETURN(HA_ERR_TABLE_READONLY);
- // JAN: TODO: MySQL 5.7
- //DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
+ DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
}
DBUG_RETURN(parse_table_name(name));
@@ -13901,14 +14387,14 @@ create_table_info_t::create_table()
/* Look for a primary key */
primary_key_no = (m_form->s->primary_key != MAX_KEY ?
- (int) m_form->s->primary_key :
- -1);
+ (int) m_form->s->primary_key : -1);
/* Our function innobase_get_mysql_key_number_for_index assumes
the primary key is always number 0, if it exists */
ut_a(primary_key_no == -1 || primary_key_no == 0);
error = create_table_def();
+
if (error) {
DBUG_RETURN(error);
}
@@ -14058,7 +14544,7 @@ create_table_info_t::create_table()
" table where referencing columns appear"
" as the first columns.\n", m_table_name);
break;
- /* JAN: TODO: MySQL 5.7 Virtual columns
+#ifdef MYSQL_VIRTUAL_COLUMNS
case DB_NO_FK_ON_V_BASE_COL:
push_warning_printf(
m_thd, Sql_condition::WARN_LEVEL_WARN,
@@ -14070,7 +14556,7 @@ create_table_info_t::create_table()
" on columns being part of virtual index.\n",
m_table_name);
break;
- */
+#endif
default:
break;
}
@@ -14112,6 +14598,7 @@ create_table_info_t::create_table_update_dict()
innobase_table = thd_to_innodb_session(m_thd)->lookup_table_handler(
m_table_name);
+
if (innobase_table == NULL) {
innobase_table = dict_table_open_on_name(
m_table_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
@@ -14351,9 +14838,7 @@ ha_innobase::discard_or_import_tablespace(
ib_senderrf(
m_prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
- ER_READ_ONLY_MODE);
- // JAN: TODO: MySQL 5.7
- //ER_CANNOT_DISCARD_TEMPORARY_TABLE);
+ ER_CANNOT_DISCARD_TEMPORARY_TABLE);
DBUG_RETURN(HA_ERR_TABLE_NEEDS_UPGRADE);
}
@@ -14374,16 +14859,16 @@ ha_innobase::discard_or_import_tablespace(
MYF(0), discard ? "discard" : "import",
dict_table->name.m_name);
- // JAN: TODO: MySQL 5.7
- //DBUG_RETURN(HA_ERR_NOT_ALLOWED_COMMAND);
- DBUG_RETURN(HA_ERR_TABLE_READONLY);
+ DBUG_RETURN(HA_ERR_NOT_ALLOWED_COMMAND);
}
TrxInInnoDB trx_in_innodb(m_prebuilt->trx);
if (trx_in_innodb.is_aborted()) {
+ innobase_rollback(ht, m_user_thd, false);
- DBUG_RETURN(innobase_rollback(ht, m_user_thd, false));
+ DBUG_RETURN(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd));
}
trx_start_if_not_started(m_prebuilt->trx, true);
@@ -14463,25 +14948,6 @@ ha_innobase::discard_or_import_tablespace(
}
}
- if (err == DB_SUCCESS && !discard
- && dict_stats_is_persistent_enabled(dict_table)) {
- dberr_t ret;
-
- /* Adjust the persistent statistics. */
- ret = dict_stats_update(dict_table,
- DICT_STATS_RECALC_PERSISTENT);
-
- if (ret != DB_SUCCESS) {
- push_warning_printf(
- ha_thd(),
- Sql_condition::WARN_LEVEL_WARN,
- ER_ALTER_INFO,
- "Error updating stats for table '%s'"
- " after table rebuild: %s",
- dict_table->name, ut_strerr(ret));
- }
- }
-
DBUG_RETURN(convert_error_code_to_mysql(err, dict_table->flags, NULL));
}
@@ -14638,6 +15104,39 @@ ha_innobase::delete_table(
norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB,
false, handler);
+ if (err == DB_TABLE_NOT_FOUND
+ && innobase_get_lower_case_table_names() == 1) {
+ char* is_part = NULL;
+#ifdef __WIN__
+ is_part = strstr(norm_name, "#p#");
+#else
+ is_part = strstr(norm_name, "#P#");
+#endif /* __WIN__ */
+
+ if (is_part) {
+ char par_case_name[FN_REFLEN];
+
+#ifndef __WIN__
+ /* Check for the table using lower
+ case name, including the partition
+ separator "P" */
+ strcpy(par_case_name, norm_name);
+ innobase_casedn_str(par_case_name);
+#else
+ /* On Windows platfrom, check
+ whether there exists table name in
+ system table whose name is
+ not being normalized to lower case */
+ normalize_table_name_c_low(
+ par_case_name, name, FALSE);
+#endif
+ err = row_drop_table_for_mysql(
+ par_case_name, trx,
+ thd_sql_command(thd) == SQLCOM_DROP_DB,
+ FALSE);
+ }
+ }
+
if (err == DB_TABLE_NOT_FOUND) {
/* Test to drop all tables which matches db/tablename + '#'.
Only partitions can have '#' as non-first character in
@@ -14725,101 +15224,7 @@ ha_innobase::delete_table(
DBUG_RETURN(convert_error_code_to_mysql(err, 0, NULL));
}
-/*****************************************************************//**
-Defragment table.
-@return error number */
-UNIV_INTERN
-int
-ha_innobase::defragment_table(
-/*==========================*/
- const char* name, /*!< in: table name */
- const char* index_name, /*!< in: index name */
- bool async) /*!< in: whether to wait until finish */
-{
- char norm_name[FN_REFLEN];
- dict_table_t* table = NULL;
- dict_index_t* index = NULL;
- ibool one_index = (index_name != 0);
- int ret = 0;
- dberr_t err = DB_SUCCESS;
-
- if (!srv_defragment) {
- return ER_FEATURE_DISABLED;
- }
-
- normalize_table_name(norm_name, name);
-
- table = dict_table_open_on_name(norm_name, FALSE,
- FALSE, DICT_ERR_IGNORE_NONE);
-
- for (index = dict_table_get_first_index(table); index;
- index = dict_table_get_next_index(index)) {
-
- if (one_index && strcasecmp(index_name, index->name) != 0) {
- continue;
- }
-
- if (btr_defragment_find_index(index)) {
- // We borrow this error code. When the same index is
- // already in the defragmentation queue, issue another
- // defragmentation only introduces overhead. We return
- // an error here to let the user know this is not
- // necessary. Note that this will fail a query that's
- // trying to defragment a full table if one of the
- // indicies in that table is already in defragmentation.
- // We choose this behavior so user is aware of this
- // rather than silently defragment other indicies of
- // that table.
- ret = ER_SP_ALREADY_EXISTS;
- break;
- }
-
- os_event_t event = btr_defragment_add_index(index, async, &err);
-
- if (err != DB_SUCCESS) {
- push_warning_printf(
- current_thd,
- Sql_condition::WARN_LEVEL_WARN,
- ER_NO_SUCH_TABLE,
- "Table %s is encrypted but encryption service or"
- " used key_id is not available. "
- " Can't continue checking table.",
- index->table->name);
-
- ret = convert_error_code_to_mysql(err, 0, current_thd);
- break;
- }
-
- if (!async && event) {
- while(os_event_wait_time(event, 1000000)) {
- if (thd_killed(current_thd)) {
- btr_defragment_remove_index(index);
- ret = ER_QUERY_INTERRUPTED;
- break;
- }
- }
- os_event_destroy(event);
- }
-
- if (ret) {
- break;
- }
-
- if (one_index) {
- one_index = FALSE;
- break;
- }
- }
-
- dict_table_close(table, FALSE, FALSE);
-
- if (ret == 0 && one_index) {
- ret = ER_NO_SUCH_INDEX;
- }
-
- return ret;
-}
-
+#ifdef MYSQL_TABLESPACES
/** Validate the parameters in st_alter_tablespace
before using them in InnoDB tablespace functions.
@param[in] thd Connection
@@ -14831,16 +15236,15 @@ validate_create_tablespace_info(
THD* thd,
st_alter_tablespace* alter_info)
{
- ulint space_id;
+
+ int error = 0;
/* The parser ensures that these fields are provided. */
ut_a(alter_info->tablespace_name);
ut_a(alter_info->data_file_name);
if (high_level_read_only) {
- return (HA_ERR_TABLE_READONLY);
- // JAN: TODO: MySQL 5.7
- // return(HA_ERR_INNODB_READ_ONLY);
+ return(HA_ERR_INNODB_READ_ONLY);
}
/* From this point forward, push a warning for each problem found
@@ -14857,12 +15261,8 @@ validate_create_tablespace_info(
alter_info->tablespace_name);
error = HA_ERR_TABLESPACE_EXISTS;
}
-
- /* JAN: TODO: MySQL 5.7 FILE_BLOCK_SIZE
if (alter_info->file_block_size) {
- */
/* Check for a bad file block size. */
- /*
if (!ut_is_2pow(alter_info->file_block_size)
|| alter_info->file_block_size < UNIV_ZIP_SIZE_MIN
|| alter_info->file_block_size > UNIV_PAGE_SIZE_MAX) {
@@ -14871,9 +15271,9 @@ validate_create_tablespace_info(
" FILE_BLOCK_SIZE=%llu", MYF(0),
alter_info->file_block_size);
error = HA_WRONG_CREATE_OPTION;
- */
+
/* Don't allow a file block size larger than UNIV_PAGE_SIZE. */
- /* } else if (alter_info->file_block_size > UNIV_PAGE_SIZE) {
+ } else if (alter_info->file_block_size > UNIV_PAGE_SIZE) {
my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: Cannot create a tablespace"
" with FILE_BLOCK_SIZE=%llu because"
@@ -14881,9 +15281,9 @@ validate_create_tablespace_info(
alter_info->file_block_size,
UNIV_PAGE_SIZE);
error = HA_WRONG_CREATE_OPTION;
- */
+
/* Don't allow a compressed tablespace when page size > 16k. */
- /* } else if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF
+ } else if (UNIV_PAGE_SIZE > UNIV_PAGE_SIZE_DEF
&& alter_info->file_block_size != UNIV_PAGE_SIZE) {
my_printf_error(ER_ILLEGAL_HA_CREATE_OPTION,
"InnoDB: Cannot create a COMPRESSED"
@@ -14892,7 +15292,6 @@ validate_create_tablespace_info(
error = HA_WRONG_CREATE_OPTION;
}
}
- */
/* Validate the ADD DATAFILE name. */
char* filepath = mem_strdup(alter_info->data_file_name);
@@ -14903,20 +15302,17 @@ validate_create_tablespace_info(
ulint dirname_len = dirname_length(filepath);
const char* basename = filepath + dirname_len;
ulint basename_len = strlen(basename);
-
- // JAN: TODO: MySQL 5.7 ER_WRONG_FILE_NAME
if (basename_len < 5) {
- my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
- MYF(0),
+ my_error(ER_WRONG_FILE_NAME, MYF(0),
alter_info->data_file_name);
ut_free(filepath);
return(HA_WRONG_CREATE_OPTION);
}
+
if (memcmp(&basename[basename_len - 4], DOT_IBD, 5)) {
- my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
- MYF(0),
+ my_error(ER_WRONG_FILE_NAME, MYF(0),
alter_info->data_file_name);
- my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+ my_printf_error(ER_WRONG_FILE_NAME,
"An IBD filepath must end with `.ibd`.",
MYF(0));
ut_free(filepath);
@@ -14935,10 +15331,9 @@ validate_create_tablespace_info(
|| (colon[1] != OS_PATH_SEPARATOR)
|| NULL != strchr(&colon[1], ':')) {
#endif /* _WIN32 */
- my_error(ER_WRONG_TABLE_NAME, // ER_WRONG_FILE_NAME,
- MYF(0),
+ my_error(ER_WRONG_FILE_NAME, MYF(0),
alter_info->data_file_name);
- my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+ my_printf_error(ER_WRONG_FILE_NAME,
"Invalid use of ':'.", MYF(0));
ut_free(filepath);
return(HA_WRONG_CREATE_OPTION);
@@ -14961,10 +15356,9 @@ validate_create_tablespace_info(
Folder folder(filepath, dirname_len);
ut_free(filepath);
if (!folder.exists()) {
- my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
- MYF(0),
+ my_error(ER_WRONG_FILE_NAME, MYF(0),
alter_info->data_file_name);
- my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+ my_printf_error(ER_WRONG_FILE_NAME,
"The directory does not exist.", MYF(0));
return(HA_WRONG_CREATE_OPTION);
}
@@ -14972,10 +15366,9 @@ validate_create_tablespace_info(
/* CREATE TABLESPACE...ADD DATAFILE can be inside but not under
the datadir.*/
if (folder_mysql_datadir > folder) {
- my_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
- MYF(0),
+ my_error(ER_WRONG_FILE_NAME, MYF(0),
alter_info->data_file_name);
- my_printf_error(ER_WRONG_TABLE_NAME, //ER_WRONG_FILE_NAME,
+ my_printf_error(ER_WRONG_FILE_NAME,
"CREATE TABLESPACE data file"
" cannot be under the datadir.", MYF(0));
error = HA_WRONG_CREATE_OPTION;
@@ -14997,7 +15390,7 @@ innobase_create_tablespace(
st_alter_tablespace* alter_info)
{
trx_t* trx;
- int error;
+ int error=0;
Tablespace tablespace;
DBUG_ENTER("innobase_create_tablespace");
@@ -15036,13 +15429,12 @@ innobase_create_tablespace(
/* In FSP_FLAGS, a zip_ssize of zero means that the tablespace
holds non-compresssed tables. A non-zero zip_ssize means that
the general tablespace can ONLY contain compressed tables. */
- ulint zip_size = static_cast<ulint>(0);
- // JAN: TODO: MySQL 5.7
- //ulint zip_size = static_cast<ulint>(alter_info->file_block_size);
+ ulint zip_size = static_cast<ulint>(alter_info->file_block_size);
ut_ad(zip_size <= UNIV_PAGE_SIZE_MAX);
if (zip_size == 0) {
zip_size = UNIV_PAGE_SIZE;
}
+
bool zipped = (zip_size != UNIV_PAGE_SIZE);
page_size_t page_size(zip_size, UNIV_PAGE_SIZE, zipped);
bool atomic_blobs = page_size.is_compressed();
@@ -15053,8 +15445,7 @@ innobase_create_tablespace(
atomic_blobs, /* needed only for compressed tables */
false, /* This is not a file-per-table tablespace */
true, /* This is a general shared tablespace */
- false, /* Temporary General Tablespaces not
- allowed */
+ false, /* Temporary General Tablespaces not allowed */
false, /* Page compression is not used. */
0, /* Page compression level 0 */
ATOMIC_WRITES_DEFAULT); /* No atomic writes yet */
@@ -15098,8 +15489,7 @@ innobase_drop_tablespace(
DBUG_ASSERT(hton == innodb_hton_ptr);
if (srv_read_only_mode) {
- DBUG_RETURN(HA_ERR_TABLE_READONLY);
- //DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
+ DBUG_RETURN(HA_ERR_INNODB_READ_ONLY);
}
error = validate_tablespace_name(alter_info->tablespace_name, false);
@@ -15110,16 +15500,21 @@ innobase_drop_tablespace(
/* Be sure that this tablespace is known and valid. */
space_id = fil_space_get_id_by_name(alter_info->tablespace_name);
if (space_id == ULINT_UNDEFINED) {
- DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
- // JAN: TODO: MySQL 5.7
- // DBUG_RETURN(HA_ERR_TABLESPACE_MISSING);
+
+ space_id = dict_space_get_id(alter_info->tablespace_name);
+ if (space_id == ULINT_UNDEFINED) {
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+ // DBUG_RETURN(HA_ERR_TABLESPACE_MISSING);
+ }
+
+ /* The datafile is not open but the tablespace is in
+ sys_tablespaces, so we can try to drop the metadata. */
}
/* The tablespace can only be dropped if it is empty. */
- if (!dict_tablespace_is_empty(space_id)) {
+ if (!dict_space_is_empty(space_id)) {
DBUG_RETURN(HA_ERR_TABLE_READONLY);
- // JAN: TODO: MySQL 5.7
- // DBUG_RETURN(HA_ERR_TABLESPACE_IS_NOT_EMPTY);
+ //DBUG_RETURN(HA_ERR_TABLESPACE_IS_NOT_EMPTY);
}
/* Get the transaction associated with the current thd and make sure
@@ -15144,25 +15539,27 @@ innobase_drop_tablespace(
ib::error() << "Unable to delete the dictionary entries"
" for tablespace `" << alter_info->tablespace_name
<< "`, Space ID " << space_id;
- error = convert_error_code_to_mysql(err, 0, NULL);
- trx_rollback_for_mysql(trx);
- goto cleanup;
+ goto have_error;
}
/* Delete the physical files, fil_space_t & fil_node_t entries. */
err = fil_delete_tablespace(space_id, BUF_REMOVE_FLUSH_NO_WRITE);
- if (err != DB_SUCCESS) {
+ switch (err) {
+ case DB_TABLESPACE_NOT_FOUND:
+ /* OK if the physical file is mising.
+ We deleted the metadata. */
+ case DB_SUCCESS:
+ innobase_commit_low(trx);
+ break;
+ default:
ib::error() << "Unable to delete the tablespace `"
<< alter_info->tablespace_name
<< "`, Space ID " << space_id;
+have_error:
error = convert_error_code_to_mysql(err, 0, NULL);
trx_rollback_for_mysql(trx);
- goto cleanup;
}
- innobase_commit_low(trx);
-
-cleanup:
row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -15230,12 +15627,14 @@ innobase_alter_tablespace(
DBUG_RETURN(error);
}
+#endif /* MYSQL_TABLESPACES */
/** Remove all tables in the named database inside InnoDB.
@param[in] hton handlerton from InnoDB
@param[in] path Database path; Inside InnoDB the name of the last
directory in the path is used as the database name.
For example, in 'mysql/data/test' the database name is 'test'. */
+
static
void
innobase_drop_database(
@@ -15317,7 +15716,7 @@ innobase_drop_database(
/*********************************************************************//**
Renames an InnoDB table.
@return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
dberr_t
innobase_rename_table(
/*==================*/
@@ -15847,7 +16246,6 @@ ha_innobase::scan_time()
it we could end up returning uninitialized value to the caller,
which in the worst case could make some query plan go bogus or
issue a Valgrind warning. */
-
if (m_prebuilt == NULL) {
/* In case of derived table, Optimizer will try to fetch stat
for table even before table is create or open. In such
@@ -15887,6 +16285,13 @@ ha_innobase::read_time(
return(handler::read_time(index, ranges, rows));
}
+#ifdef MYSQL_ROWS
+ if (rows <= 2) {
+
+ return((double) rows);
+ }
+#endif
+
/* Assume that the read time is proportional to the scan time for all
rows + at most one seek per range. */
@@ -16287,7 +16692,7 @@ ha_innobase::info_low(
}
stats.check_time = 0;
- stats.mrr_length_per_rec= ref_length + 8; // 8 = max(sizeof(void *));
+ stats.mrr_length_per_rec= ref_length + 8; // 8 = max(sizeof(void *));
if (stats.records == 0) {
stats.mean_rec_length = 0;
@@ -16417,13 +16822,14 @@ ha_innobase::info_low(
calculated at different time. This is
acceptable. */
+#ifdef MYSQL_REC_PER_KEY
const rec_per_key_t rec_per_key
= innodb_rec_per_key(
index, j,
index->table->stat_n_rows);
- // JAN: TODO: MySQL 5.7 New interface
- // key->set_records_per_key(j, rec_per_key);
+ key->set_records_per_key(j, rec_per_key);
+#endif /* MYSQL_REC_PER_KEY */
/* The code below is legacy and should be
removed together with this comment once we
@@ -16618,6 +17024,101 @@ ha_innobase::analyze(
return(HA_ADMIN_OK);
}
+/*****************************************************************//**
+Defragment table.
+@return error number */
+UNIV_INTERN
+int
+ha_innobase::defragment_table(
+/*==========================*/
+ const char* name, /*!< in: table name */
+ const char* index_name, /*!< in: index name */
+ bool async) /*!< in: whether to wait until finish */
+{
+ char norm_name[FN_REFLEN];
+ dict_table_t* table = NULL;
+ dict_index_t* index = NULL;
+ ibool one_index = (index_name != 0);
+ int ret = 0;
+ dberr_t err = DB_SUCCESS;
+
+ if (!srv_defragment) {
+ return ER_FEATURE_DISABLED;
+ }
+
+ normalize_table_name(norm_name, name);
+
+ table = dict_table_open_on_name(norm_name, FALSE,
+ FALSE, DICT_ERR_IGNORE_NONE);
+
+ for (index = dict_table_get_first_index(table); index;
+ index = dict_table_get_next_index(index)) {
+
+ if (one_index && strcasecmp(index_name, index->name) != 0) {
+ continue;
+ }
+
+ if (btr_defragment_find_index(index)) {
+ // We borrow this error code. When the same index is
+ // already in the defragmentation queue, issue another
+ // defragmentation only introduces overhead. We return
+ // an error here to let the user know this is not
+ // necessary. Note that this will fail a query that's
+ // trying to defragment a full table if one of the
+ // indicies in that table is already in defragmentation.
+ // We choose this behavior so user is aware of this
+ // rather than silently defragment other indicies of
+ // that table.
+ ret = ER_SP_ALREADY_EXISTS;
+ break;
+ }
+
+ os_event_t event = btr_defragment_add_index(index, async, &err);
+
+ if (err != DB_SUCCESS) {
+ push_warning_printf(
+ current_thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ ER_NO_SUCH_TABLE,
+ "Table %s is encrypted but encryption service or"
+ " used key_id is not available. "
+ " Can't continue checking table.",
+ index->table->name);
+
+ ret = convert_error_code_to_mysql(err, 0, current_thd);
+ break;
+ }
+
+ if (!async && event) {
+ while(os_event_wait_time(event, 1000000)) {
+ if (thd_killed(current_thd)) {
+ btr_defragment_remove_index(index);
+ ret = ER_QUERY_INTERRUPTED;
+ break;
+ }
+ }
+ os_event_destroy(event);
+ }
+
+ if (ret) {
+ break;
+ }
+
+ if (one_index) {
+ one_index = FALSE;
+ break;
+ }
+ }
+
+ dict_table_close(table, FALSE, FALSE);
+
+ if (ret == 0 && one_index) {
+ ret = ER_NO_SUCH_INDEX;
+ }
+
+ return ret;
+}
+
/**********************************************************************//**
This is mapped to "ALTER TABLE tablename ENGINE=InnoDB", which rebuilds
the table in MySQL. */
@@ -16653,7 +17154,7 @@ ha_innobase::optimize(
"InnoDB: Cannot defragment table %s: returned error code %d\n",
m_prebuilt->table->name, err);
- if(err == ER_SP_ALREADY_EXISTS) {
+ if (err == ER_SP_ALREADY_EXISTS) {
return (HA_ADMIN_OK);
} else {
return (HA_ADMIN_TRY_ALTER);
@@ -16664,7 +17165,7 @@ ha_innobase::optimize(
if (innodb_optimize_fulltext_only) {
if (m_prebuilt->table->fts && m_prebuilt->table->fts->cache
&& !dict_table_is_discarded(m_prebuilt->table)) {
- fts_sync_table(m_prebuilt->table, true, false);
+ fts_sync_table(m_prebuilt->table, false, true, false);
fts_optimize_table(m_prebuilt->table);
}
return(HA_ADMIN_OK);
@@ -16727,8 +17228,10 @@ ha_innobase::check(
DBUG_RETURN(HA_ADMIN_CORRUPT);
}
+ m_prebuilt->trx->op_info = "checking table";
+
if (m_prebuilt->table->corrupted) {
- /* If some previous oeration has marked the table as
+ /* If some previous operation has marked the table as
corrupted in memory, and has not propagated such to
clustered index, we will do so here */
index = dict_table_get_first_index(m_prebuilt->table);
@@ -16831,7 +17334,7 @@ ha_innobase::check(
if (!dict_index_is_clust(index)) {
m_prebuilt->index_usable = FALSE;
// row_mysql_lock_data_dictionary(m_prebuilt->trx);
- dict_set_corrupted(index, m_prebuilt->trx, "dict_set_index_corrupted");;
+ dict_set_corrupted(index, m_prebuilt->trx, "dict_set_index_corrupted");;
// row_mysql_unlock_data_dictionary(m_prebuilt->trx);
});
@@ -16898,14 +17401,6 @@ ha_innobase::check(
index, m_prebuilt->trx, "CHECK TABLE-check index");
}
- if (thd_kill_level(m_user_thd)) {
- break;
- }
-
-#if 0
- fprintf(stderr, "%lu entries in index %s\n", n_rows,
- index->name);
-#endif
if (index == dict_table_get_first_index(m_prebuilt->table)) {
n_rows_in_table = n_rows;
@@ -16999,11 +17494,8 @@ ha_innobase::update_table_comment(
} else if (length + flen + 3 > 64000) {
flen = 64000 - 3 - length;
}
-
/* allocate buffer for the full string */
-
str = (char*) my_malloc(length + flen + 3, MYF(0));
-
if (str) {
char* pos = str + length;
if (length) {
@@ -17011,7 +17503,6 @@ ha_innobase::update_table_comment(
*pos++ = ';';
*pos++ = ' ';
}
-
memcpy(pos, fk_str.c_str(), flen);
pos[flen] = 0;
}
@@ -17048,6 +17539,7 @@ ha_innobase::get_foreign_key_create_info(void)
trx_search_latch_release_if_reserved(m_prebuilt->trx);
+
/* Output the data to a temporary string */
std::string str = dict_print_info_on_foreign_keys(
TRUE, m_prebuilt->trx,
@@ -17063,6 +17555,8 @@ ha_innobase::get_foreign_key_create_info(void)
my_malloc(PSI_INSTRUMENT_ME, str.length() + 1, MYF(0)));
*/
+
+
if (fk_str) {
memcpy(fk_str, str.c_str(), str.length());
fk_str[str.length()]='\0';
@@ -17581,7 +18075,7 @@ ha_innobase::end_stmt()
reset_template();
- //m_ds_mrr.reset();
+ m_ds_mrr.dsmrr_close();
/* TODO: This should really be reset in reset_template() but for now
it's safer to do it explicitly here. */
@@ -17862,6 +18356,14 @@ ha_innobase::external_lock(
&& thd_sql_command(thd) == SQLCOM_FLUSH
&& lock_type == F_RDLCK) {
+ if (dict_table_is_discarded(m_prebuilt->table)) {
+ ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
+ ER_TABLESPACE_DISCARDED,
+ table->s->table_name.str);
+
+ DBUG_RETURN(HA_ERR_NO_SUCH_TABLE);
+ }
+
row_quiesce_table_start(m_prebuilt->table, trx);
/* Use the transaction instance to track UNLOCK
@@ -18109,9 +18611,9 @@ innodb_show_status(
/* JAN: TODO: MySQL 5.7 PSI */
if (!(str = (char*) my_malloc(
- usable_len + 1, MYF(0)))) {
+ usable_len + 1, MYF(0)))) {
/* if (!(str = (char*) my_malloc(PSI_INSTRUMENT_ME,
- usable_len + 1, MYF(0)))) {
+ usable_len + 1, MYF(0)))) {
*/
mutex_exit(&srv_monitor_file_mutex);
DBUG_RETURN(1);
@@ -18168,7 +18670,7 @@ struct ShowStatus {
Value(const char* name,
ulint spins,
uint64_t waits,
- ulint calls)
+ uint64_t calls)
:
m_name(name),
m_spins(spins),
@@ -18185,7 +18687,7 @@ struct ShowStatus {
ulint m_spins;
/** Waits so far */
- ulint m_waits;
+ uint64_t m_waits;
/** Number of calls so far */
uint64_t m_calls;
@@ -18325,10 +18827,10 @@ ShowStatus::to_string(
status_len = ut_snprintf(
status_buf, sizeof(status_buf),
- "spins=%lu,waits=%lu,calls=" TRX_ID_FMT,
+ "spins=%lu,waits=%lu,calls=%llu",
static_cast<ulong>(it->m_spins),
static_cast<long>(it->m_waits),
- it->m_calls);
+ (ulonglong) it->m_calls);
if (stat_print(thd, innobase_hton_name,
hton_name_len,
@@ -18519,56 +19021,6 @@ innobase_show_status(
return(false);
}
-/** Refresh template for the virtual columns and their base columns if
-the share structure exists
-@param[in] table MySQL TABLE
-@param[in] ib_table InnoDB dict_table_t
-@param[in] table_name table_name used to find the share structure */
-void
-refresh_share_vtempl(
- const TABLE* mysql_table,
- const dict_table_t* ib_table,
- const char* table_name)
-{
- INNOBASE_SHARE* share;
-
- ulint fold = ut_fold_string(table_name);
-
- mysql_mutex_lock(&innobase_share_mutex);
-
- HASH_SEARCH(table_name_hash, innobase_open_tables, fold,
- INNOBASE_SHARE*, share,
- ut_ad(share->use_count > 0),
- !strcmp(share->table_name, table_name));
-
- if (share == NULL) {
- /* Partition table does not have "share" structure
- instantiated, no need to refresh it */
-#ifdef UNIV_DEBUG
- #ifdef _WIN32
- char* is_part = strstr(ib_table->name.m_name, "#p#");
- #else
- char* is_part = strstr(ib_table->name.m_name, "#P#");
- #endif /* _WIN32 */
-
- ut_ad(is_part != NULL);
-#endif /* UNIV_DEBUG */
-
- mysql_mutex_unlock(&innobase_share_mutex);
- return;
- }
-
- free_share_vtemp(share);
-
- innobase_build_v_templ(
- mysql_table, ib_table, &(share->s_templ), NULL, true,
- share->table_name);
-
- mysql_mutex_unlock(&innobase_share_mutex);
-
- return;
-}
-
/************************************************************************//**
Handling the shared INNOBASE_SHARE structure that is needed to provide table
locking. Register the table name if it doesn't exist in the hash table. */
@@ -18613,12 +19065,12 @@ get_share(
HASH_INSERT(INNOBASE_SHARE, table_name_hash,
innobase_open_tables, fold, share);
+ thr_lock_init(&share->lock);
+
/* Index translation table initialization */
share->idx_trans_tbl.index_mapping = NULL;
share->idx_trans_tbl.index_count = 0;
share->idx_trans_tbl.array_size = 0;
- share->s_templ.vtempl = NULL;
- share->s_templ.n_col = 0;
}
++share->use_count;
@@ -18628,15 +19080,6 @@ get_share(
return(share);
}
-/** Free a virtual template in INNOBASE_SHARE structure
-@param[in,out] share table share holds the template to free */
-void
-free_share_vtemp(
- INNOBASE_SHARE* share)
-{
- free_vc_templ(&share->s_templ);
-}
-
/************************************************************************//**
Free the shared object that was registered with get_share(). */
static
@@ -18667,11 +19110,11 @@ free_share(
HASH_DELETE(INNOBASE_SHARE, table_name_hash,
innobase_open_tables, fold, share);
+ thr_lock_delete(&share->lock);
+
/* Free any memory from index translation table */
ut_free(share->idx_trans_tbl.index_mapping);
- free_share_vtemp(share);
-
my_free(share);
/* TODO: invoke HASH_MIGRATE if innobase_open_tables
@@ -18681,6 +19124,7 @@ free_share(
mysql_mutex_unlock(&innobase_share_mutex);
}
+#if 0
/*********************************************************************//**
Returns number of THR_LOCK locks used for one instance of InnoDB table.
InnoDB no longer relies on THR_LOCK locks so 0 value is returned.
@@ -18696,6 +19140,7 @@ ha_innobase::lock_count(void) const
{
return 0;
}
+#endif
/*****************************************************************//**
Supposed to convert a MySQL table lock stored in the 'lock' field of the
@@ -18875,6 +19320,75 @@ ha_innobase::store_lock(
m_prebuilt->stored_select_lock_type = LOCK_NONE;
}
+ if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK) {
+
+ /* Starting from 5.0.7, we weaken also the table locks
+ set at the start of a MySQL stored procedure call, just like
+ we weaken the locks set at the start of an SQL statement.
+ MySQL does set in_lock_tables TRUE there, but in reality
+ we do not need table locks to make the execution of a
+ single transaction stored procedure call deterministic
+ (if it does not use a consistent read). */
+
+ if (lock_type == TL_READ
+ && sql_command == SQLCOM_LOCK_TABLES) {
+ /* We come here if MySQL is processing LOCK TABLES
+ ... READ LOCAL. MyISAM under that table lock type
+ reads the table as it was at the time the lock was
+ granted (new inserts are allowed, but not seen by the
+ reader). To get a similar effect on an InnoDB table,
+ we must use LOCK TABLES ... READ. We convert the lock
+ type here, so that for InnoDB, READ LOCAL is
+ equivalent to READ. This will change the InnoDB
+ behavior in mysqldump, so that dumps of InnoDB tables
+ are consistent with dumps of MyISAM tables. */
+
+ lock_type = TL_READ_NO_INSERT;
+ }
+
+ /* If we are not doing a LOCK TABLE, DISCARD/IMPORT
+ TABLESPACE or TRUNCATE TABLE then allow multiple
+ writers. Note that ALTER TABLE uses a TL_WRITE_ALLOW_READ
+ < TL_WRITE_CONCURRENT_INSERT.
+
+ We especially allow multiple writers if MySQL is at the
+ start of a stored procedure call (SQLCOM_CALL) or a
+ stored function call (MySQL does have in_lock_tables
+ TRUE there). */
+
+ if ((lock_type >= TL_WRITE_CONCURRENT_INSERT
+ && lock_type <= TL_WRITE)
+ && !(in_lock_tables
+ && sql_command == SQLCOM_LOCK_TABLES)
+ && !thd_tablespace_op(thd)
+ && sql_command != SQLCOM_TRUNCATE
+ && sql_command != SQLCOM_OPTIMIZE
+ && sql_command != SQLCOM_CREATE_TABLE) {
+
+ lock_type = TL_WRITE_ALLOW_WRITE;
+ }
+
+ /* In queries of type INSERT INTO t1 SELECT ... FROM t2 ...
+ MySQL would use the lock TL_READ_NO_INSERT on t2, and that
+ would conflict with TL_WRITE_ALLOW_WRITE, blocking all inserts
+ to t2. Convert the lock to a normal read lock to allow
+ concurrent inserts to t2.
+
+ We especially allow concurrent inserts if MySQL is at the
+ start of a stored procedure call (SQLCOM_CALL)
+ (MySQL does have thd_in_lock_tables() TRUE there). */
+
+ if (lock_type == TL_READ_NO_INSERT
+ && sql_command != SQLCOM_LOCK_TABLES) {
+
+ lock_type = TL_READ;
+ }
+
+ lock.type = lock_type;
+ }
+
+ *to++= &lock;
+
if (!trx_is_started(trx)
&& (m_prebuilt->select_lock_type != LOCK_NONE
|| m_prebuilt->stored_select_lock_type != LOCK_NONE)) {
@@ -18883,7 +19397,7 @@ ha_innobase::store_lock(
}
#ifdef UNIV_DEBUG
- if(trx->is_dd_trx) {
+ if (trx->is_dd_trx) {
ut_ad(trx->will_lock == 0
&& m_prebuilt->select_lock_type == LOCK_NONE);
}
@@ -19022,16 +19536,22 @@ ha_innobase::get_auto_increment(
/* Not in the middle of a mult-row INSERT. */
} else if (m_prebuilt->autoinc_last_value == 0) {
set_if_bigger(*first_value, autoinc);
+ /* Check for -ve values. */
+ /* JAN: TODO: MySQL 5.7 : */
+ // } else if (*first_value > col_max_value && trx->n_autoinc_rows > 0) {
+ /* Set to next logical value. */
+ // ut_a(autoinc > trx->n_autoinc_rows);
+ //*first_value = (autoinc - trx->n_autoinc_rows) - 1;
}
- if (*first_value > col_max_value) {
- /* Out of range number. Let handler::update_auto_increment()
- take care of this */
- m_prebuilt->autoinc_last_value = 0;
- dict_table_autoinc_unlock(m_prebuilt->table);
- *nb_reserved_values= 0;
- return;
- }
+ if (*first_value > col_max_value) {
+ /* Out of range number. Let handler::update_auto_increment()
+ take care of this */
+ m_prebuilt->autoinc_last_value = 0;
+ dict_table_autoinc_unlock(m_prebuilt->table);
+ *nb_reserved_values= 0;
+ return;
+ }
*nb_reserved_values = trx->n_autoinc_rows;
@@ -19265,7 +19785,6 @@ ha_innobase::register_query_cache_table(
ulonglong *engine_data) /*!< in/out: data to call_back */
{
*engine_data = 0;
-
*call_back = innobase_query_caching_of_table_permitted;
return(innobase_query_caching_of_table_permitted(
@@ -19363,13 +19882,6 @@ innobase_xa_prepare(
DBUG_ASSERT(hton == innodb_hton_ptr);
- /* we use support_xa value as it was seen at transaction start
- time, not the current session variable value. Any possible changes
- to the session variable take effect only in the next transaction */
- if (!trx->support_xa) {
- return(0);
- }
-
thd_get_xid(thd, (MYSQL_XID*) trx->xid);
/* Release a possible FIFO ticket and search latch. Since we will
@@ -19384,7 +19896,10 @@ innobase_xa_prepare(
if (trx_in_innodb.is_aborted()) {
- return(innobase_rollback(hton, thd, prepare_trx));
+ innobase_rollback(hton, thd, prepare_trx);
+
+ return(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, thd));
}
if (!trx_is_registered_for_2pc(trx) && trx_is_started(trx)) {
@@ -19406,7 +19921,11 @@ innobase_xa_prepare(
ut_ad(err == DB_SUCCESS || err == DB_FORCED_ABORT);
if (err == DB_FORCED_ABORT) {
- return(innobase_rollback(hton, thd, prepare_trx));
+
+ innobase_rollback(hton, thd, prepare_trx);
+
+ return(convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, thd));
}
} else {
@@ -19425,6 +19944,24 @@ innobase_xa_prepare(
trx_mark_sql_stat_end(trx);
}
+ if (thd_sql_command(thd) != SQLCOM_XA_PREPARE
+ && (prepare_trx
+ || !thd_test_options(
+ thd, OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))) {
+
+ /* For mysqlbackup to work the order of transactions in binlog
+ and InnoDB must be the same. Consider the situation
+
+ thread1> prepare; write to binlog; ...
+ <context switch>
+ thread2> prepare; write to binlog; commit
+ thread1> ... commit
+
+ The server guarantees that writes to the binary log
+ and commits are in the same order, so we do not have
+ to handle this case. */
+ }
+
return(0);
}
@@ -19468,7 +20005,7 @@ innobase_commit_by_xid(
TrxInInnoDB trx_in_innodb(trx);
innobase_commit_low(trx);
- ut_ad(trx->mysql_thd == NULL);
+ ut_ad(trx->mysql_thd == NULL);
/* use cases are: disconnected xa, slave xa, recovery */
trx_deregister_from_2pc(trx);
ut_ad(!trx->will_lock); /* trx cache requirement */
@@ -19511,6 +20048,8 @@ innobase_rollback_by_xid(
}
}
+#ifdef INNOBASE_CURSOR_VIEW
+
/*******************************************************************//**
Create a consistent view for a cursor based on current transaction
which is created if the corresponding MySQL thread still lacks one.
@@ -19526,9 +20065,7 @@ innobase_create_cursor_view(
{
DBUG_ASSERT(hton == innodb_hton_ptr);
- return NULL;
- // JAN: TODO: MySQL 5.7 Needed ?
- // return(read_cursor_view_create_for_mysql(check_trx_exists(thd)));
+ return(read_cursor_view_create_for_mysql(check_trx_exists(thd)));
}
/*******************************************************************//**
@@ -19545,10 +20082,8 @@ innobase_close_cursor_view(
{
DBUG_ASSERT(hton == innodb_hton_ptr);
- /* JAN: TODO: MySQL 5.7 Needed
read_cursor_view_close_for_mysql(check_trx_exists(thd),
(cursor_view_t*) curview);
- */
}
/*******************************************************************//**
@@ -19566,14 +20101,10 @@ innobase_set_cursor_view(
{
DBUG_ASSERT(hton == innodb_hton_ptr);
- /* JAN: TODO: MySQL 5.7 Needed ?
read_cursor_set_for_mysql(check_trx_exists(thd),
(cursor_view_t*) curview);
- */
}
-
-/*******************************************************************//**
-*/
+#endif /* INNOBASE_CURSOR_VIEW */
bool
ha_innobase::check_if_incompatible_data(
@@ -19650,7 +20181,7 @@ innodb_io_capacity_max_update(
srv_io_capacity = in_val;
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WRONG_ARGUMENTS,
+ ER_WRONG_ARGUMENTS,
"Setting innodb_io_capacity to %lu",
srv_io_capacity);
}
@@ -19679,8 +20210,8 @@ innodb_io_capacity_update(
push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
ER_WRONG_ARGUMENTS,
"Setting innodb_io_capacity to %lu"
- " higher than innodb_io_capacity_max %lu",
- in_val, srv_max_io_capacity);
+ " higher than innodb_io_capacity_max %lu",
+ in_val, srv_max_io_capacity);
srv_max_io_capacity = in_val * 2;
@@ -19760,13 +20291,6 @@ innodb_max_dirty_pages_pct_lwm_update(
srv_max_dirty_pages_pct_lwm = in_val;
}
-UNIV_INTERN
-void
-ha_innobase::set_partition_owner_stats(ha_statistics *stats)
-{
- ha_partition_stats= stats;
-}
-
/************************************************************//**
Validate the file format name and return its corresponding id.
@return valid file format id */
@@ -20038,7 +20562,6 @@ innodb_large_prefix_update(
void* var_ptr,
const void* save)
{
-
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
HA_ERR_WRONG_COMMAND, deprecated_large_prefix);
@@ -20114,99 +20637,6 @@ innodb_buffer_pool_size_update(
<< " (new size: " << in_val << " bytes)";
}
-/** Validate the requested buffer pool size. Also, reserve the necessary
-memory needed for buffer pool resize.
-@param[in] thd thread handle
-@param[in] var pointer to system variable
-@param[out] save immediate result for update function
-@param[in] value incoming string
-@return 0 on success, 1 on failure.
-*/
-static
-int
-innodb_buffer_pool_size_validate(
- THD* thd,
- struct st_mysql_sys_var* var,
- void* save,
- struct st_mysql_value* value)
-{
- longlong intbuf;
-
-
- value->val_int(value, &intbuf);
-
- if (!srv_was_started) {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WRONG_ARGUMENTS,
- "Cannot update innodb_buffer_pool_size,"
- " because InnoDB is not started.");
- return(1);
- }
-
-#ifdef UNIV_DEBUG
- if (buf_disable_resize_buffer_pool_debug == TRUE) {
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WRONG_ARGUMENTS,
- "Cannot update innodb_buffer_pool_size,"
- " because innodb_disable_resize_buffer_pool_debug"
- " is set.");
- ib::warn() << "Cannot update innodb_buffer_pool_size,"
- " because innodb_disable_resize_buffer_pool_debug"
- " is set.";
- return(1);
- }
-#endif /* UNIV_DEBUG */
-
-
- buf_pool_mutex_enter_all();
-
- if (srv_buf_pool_old_size != srv_buf_pool_size) {
- buf_pool_mutex_exit_all();
- // JAN: TODO: MySQL 5.7 New error
- // my_error(ER_BUFPOOL_RESIZE_INPROGRESS, MYF(0));
- my_error(ER_WRONG_ARGUMENTS, MYF(0));
- return(1);
- }
-
- if (srv_buf_pool_instances > 1 && intbuf < BUF_POOL_SIZE_THRESHOLD) {
- buf_pool_mutex_exit_all();
-
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_WRONG_ARGUMENTS,
- "Cannot update innodb_buffer_pool_size"
- " to less than 1GB if"
- " innodb_buffer_pool_instances > 1.");
- return(1);
- }
-
- ulint requested_buf_pool_size
- = buf_pool_size_align(static_cast<ulint>(intbuf));
-
- *static_cast<longlong*>(save) = requested_buf_pool_size;
-
- if (srv_buf_pool_size == requested_buf_pool_size) {
- buf_pool_mutex_exit_all();
- /* nothing to do */
- return(0);
- }
-
- srv_buf_pool_size = requested_buf_pool_size;
- buf_pool_mutex_exit_all();
-
- if (intbuf != static_cast<longlong>(requested_buf_pool_size)) {
- char buf[64];
- int len = 64;
- value->val_str(value, buf, &len);
- push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
- ER_TRUNCATED_WRONG_VALUE,
- "innodb_buffer_pool_size",
- // mysql_sysvar_buffer_pool_size.name,
- value->val_str(value, buf, &len));
- }
-
- return(0);
-}
-
/*************************************************************//**
Check whether valid argument given to "innodb_fts_internal_tbl_name"
This function is registered as a callback with MySQL.
@@ -20391,6 +20821,11 @@ innodb_make_page_dirty(
return;
}
+ if (srv_saved_page_number_debug > space->size) {
+ fil_space_release(space);
+ return;
+ }
+
mtr.start();
mtr.set_named_space(space);
@@ -20829,7 +21264,7 @@ innodb_monitor_validate(
name, MYF(0));
*/
monitor_name = my_strdup(
- name, MYF(0));
+ name, MYF(0));
} else {
return(1);
}
@@ -21174,9 +21609,9 @@ innodb_defragment_frequency_update(
static inline char *my_strtok_r(char *str, const char *delim, char **saveptr)
{
#if defined _WIN32
- return strtok_s(str, delim, saveptr);
+ return strtok_s(str, delim, saveptr);
#else
- return strtok_r(str, delim, saveptr);
+ return strtok_r(str, delim, saveptr);
#endif
}
@@ -21310,10 +21745,8 @@ innobase_fts_close_ranking(
/*=======================*/
FT_INFO * fts_hdl)
{
- reinterpret_cast<NEW_FT_INFO*>(fts_hdl)->ft_prebuilt->in_fts_query =
- false;
-
fts_result_t* result;
+
result = reinterpret_cast<NEW_FT_INFO*>(fts_hdl)->ft_result;
fts_query_free_result(result);
@@ -21346,6 +21779,7 @@ innobase_fts_find_ranking(
}
#ifdef UNIV_DEBUG
+static my_bool innodb_background_drop_list_empty = TRUE;
static my_bool innodb_purge_run_now = TRUE;
static my_bool innodb_purge_stop_now = TRUE;
static my_bool innodb_log_checkpoint_now = TRUE;
@@ -21353,6 +21787,24 @@ static my_bool innodb_buf_flush_list_now = TRUE;
static uint innodb_merge_threshold_set_all_debug
= DICT_INDEX_MERGE_THRESHOLD_DEFAULT;
+/** Wait for the background drop list to become empty. */
+static
+void
+wait_background_drop_list_empty(
+ THD* thd /*!< in: thread handle */
+ MY_ATTRIBUTE((unused)),
+ struct st_mysql_sys_var* var /*!< in: pointer to system
+ variable */
+ MY_ATTRIBUTE((unused)),
+ void* var_ptr /*!< out: where the formal
+ string goes */
+ MY_ATTRIBUTE((unused)),
+ const void* save) /*!< in: immediate result from
+ check function */
+{
+ row_wait_for_background_drop_list_empty();
+}
+
/****************************************************************//**
Set the purge state to RUN. If purge is disabled then it
is a no-op. This function is registered as a callback with MySQL. */
@@ -21426,7 +21878,11 @@ checkpoint_now_set(
fil_flush_file_spaces(FIL_TYPE_LOG);
}
- fil_write_flushed_lsn(log_sys->lsn);
+ dberr_t err = fil_write_flushed_lsn(log_sys->lsn);
+
+ if (err != DB_SUCCESS) {
+ ib::warn() << "Checkpoint set failed " << err;
+ }
}
}
@@ -21584,13 +22040,13 @@ void
buffer_pool_load_now(
/*=================*/
THD* thd /*!< in: thread handle */
- __attribute__((unused)),
+ MY_ATTRIBUTE((unused)),
struct st_mysql_sys_var* var /*!< in: pointer to system
variable */
- __attribute__((unused)),
+ MY_ATTRIBUTE((unused)),
void* var_ptr /*!< out: where the formal
string goes */
- __attribute__((unused)),
+ MY_ATTRIBUTE((unused)),
const void* save) /*!< in: immediate result from
check function */
{
@@ -21607,13 +22063,13 @@ void
buffer_pool_load_abort(
/*===================*/
THD* thd /*!< in: thread handle */
- __attribute__((unused)),
+ MY_ATTRIBUTE((unused)),
struct st_mysql_sys_var* var /*!< in: pointer to system
variable */
- __attribute__((unused)),
+ MY_ATTRIBUTE((unused)),
void* var_ptr /*!< out: where the formal
string goes */
- __attribute__((unused)),
+ MY_ATTRIBUTE((unused)),
const void* save) /*!< in: immediate result from
check function */
{
@@ -22194,6 +22650,12 @@ static MYSQL_SYSVAR_ULONG(idle_flush_pct,
NULL, NULL, 100, 0, 100, 0);
#ifdef UNIV_DEBUG
+static MYSQL_SYSVAR_BOOL(background_drop_list_empty,
+ innodb_background_drop_list_empty,
+ PLUGIN_VAR_OPCMDARG,
+ "Wait for the background drop list to become empty",
+ NULL, wait_background_drop_list_empty, FALSE);
+
static MYSQL_SYSVAR_BOOL(purge_run_now, innodb_purge_run_now,
PLUGIN_VAR_OPCMDARG,
"Set purge state to RUN",
@@ -22769,7 +23231,7 @@ static MYSQL_SYSVAR_LONG(log_buffer_size, innobase_log_buffer_size,
static MYSQL_SYSVAR_LONGLONG(log_file_size, innobase_log_file_size,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Size of each log file in a log group.",
- NULL, NULL, 48*1024*1024L, 1*1024*1024L, LLONG_MAX, 1024*1024L);
+ NULL, NULL, 48*1024*1024L, 4*1024*1024L, LLONG_MAX, 1024*1024L);
static MYSQL_SYSVAR_ULONG(log_files_in_group, srv_n_log_files,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
@@ -22920,12 +23382,12 @@ static MYSQL_SYSVAR_BOOL(use_native_aio, srv_use_native_aio,
"Use native AIO if supported on this platform.",
NULL, NULL, TRUE);
-#ifdef HAVE_LIBNUMA
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
static MYSQL_SYSVAR_BOOL(numa_interleave, srv_numa_interleave,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
"Use NUMA interleave memory policy to allocate InnoDB buffer pool.",
NULL, NULL, FALSE);
-#endif // HAVE_LIBNUMA
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
static MYSQL_SYSVAR_BOOL(api_enable_binlog, ib_binlog_enabled,
PLUGIN_VAR_NOCMDARG | PLUGIN_VAR_READONLY,
@@ -22994,7 +23456,7 @@ static MYSQL_SYSVAR_BOOL(disable_background_merge,
static MYSQL_SYSVAR_ENUM(compress_debug, srv_debug_compress,
PLUGIN_VAR_RQCMDARG,
- "Compress all tables, without specifying the COMRPESS table attribute",
+ "Compress all tables, without specifying the COMPRESS table attribute",
NULL, NULL, Compression::NONE, &innodb_debug_compress_typelib);
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
@@ -23154,16 +23616,34 @@ static MYSQL_SYSVAR_BOOL(disable_resize_buffer_pool_debug,
"Disable resizing buffer pool to make assertion code not expensive.",
NULL, NULL, TRUE);
+static MYSQL_SYSVAR_BOOL(page_cleaner_disabled_debug,
+ innodb_page_cleaner_disabled_debug,
+ PLUGIN_VAR_OPCMDARG,
+ "Disable page cleaner",
+ NULL, buf_flush_page_cleaner_disabled_debug_update, FALSE);
+
static MYSQL_SYSVAR_BOOL(sync_debug, srv_sync_debug,
PLUGIN_VAR_OPCMDARG | PLUGIN_VAR_READONLY,
"Enable the sync debug checks",
NULL, NULL, FALSE);
-#endif /* UNIV_DEBUG */
+
+static MYSQL_SYSVAR_BOOL(dict_stats_disabled_debug,
+ innodb_dict_stats_disabled_debug,
+ PLUGIN_VAR_OPCMDARG,
+ "Disable dict_stats thread",
+ NULL, dict_stats_disabled_debug_update, FALSE);
+
+static MYSQL_SYSVAR_BOOL(master_thread_disabled_debug,
+ srv_master_thread_disabled_debug,
+ PLUGIN_VAR_OPCMDARG,
+ "Disable master thread",
+ NULL, srv_master_thread_disabled_debug_update, FALSE);
static MYSQL_SYSVAR_UINT(simulate_comp_failures, srv_simulate_comp_failures,
PLUGIN_VAR_NOCMDARG,
"Simulate compression failures.",
NULL, NULL, 0, 0, 99, 0);
+#endif /* UNIV_DEBUG */
static MYSQL_SYSVAR_BOOL(force_primary_key,
srv_force_primary_key,
@@ -23443,12 +23923,13 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(adaptive_max_sleep_delay),
MYSQL_SYSVAR(prefix_index_cluster_optimization),
MYSQL_SYSVAR(thread_sleep_delay),
+ MYSQL_SYSVAR(tmpdir),
MYSQL_SYSVAR(autoinc_lock_mode),
MYSQL_SYSVAR(version),
MYSQL_SYSVAR(use_native_aio),
-#ifdef HAVE_LIBNUMA
+#if defined(HAVE_LIBNUMA) && defined(WITH_NUMA)
MYSQL_SYSVAR(numa_interleave),
-#endif // HAVE_LIBNUMA
+#endif /* HAVE_LIBNUMA && WITH_NUMA */
MYSQL_SYSVAR(change_buffering),
MYSQL_SYSVAR(change_buffer_max_size),
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
@@ -23472,6 +23953,7 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(purge_threads),
MYSQL_SYSVAR(purge_batch_size),
#ifdef UNIV_DEBUG
+ MYSQL_SYSVAR(background_drop_list_empty),
MYSQL_SYSVAR(purge_run_now),
MYSQL_SYSVAR(purge_stop_now),
MYSQL_SYSVAR(log_checkpoint_now),
@@ -23497,8 +23979,8 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(compression_failure_threshold_pct),
MYSQL_SYSVAR(compression_pad_pct_max),
MYSQL_SYSVAR(default_row_format),
- MYSQL_SYSVAR(simulate_comp_failures),
#ifdef UNIV_DEBUG
+ MYSQL_SYSVAR(simulate_comp_failures),
MYSQL_SYSVAR(trx_rseg_n_slots_debug),
MYSQL_SYSVAR(limit_optimistic_insert_debug),
MYSQL_SYSVAR(trx_purge_view_update_only_debug),
@@ -23506,6 +23988,9 @@ static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(saved_page_number_debug),
MYSQL_SYSVAR(compress_debug),
MYSQL_SYSVAR(disable_resize_buffer_pool_debug),
+ MYSQL_SYSVAR(page_cleaner_disabled_debug),
+ MYSQL_SYSVAR(dict_stats_disabled_debug),
+ MYSQL_SYSVAR(master_thread_disabled_debug),
MYSQL_SYSVAR(sync_debug),
#endif /* UNIV_DEBUG */
MYSQL_SYSVAR(tmpdir),
@@ -23638,12 +24123,13 @@ ha_innobase::multi_range_read_init(
uint mode,
HANDLER_BUFFER* buf)
{
- return(m_ds_mrr.dsmrr_init(this, seq, seq_init_param, n_ranges, mode, buf));
+ return(m_ds_mrr.dsmrr_init(this, seq, seq_init_param,
+ n_ranges, mode, buf));
}
int
ha_innobase::multi_range_read_next(
- range_id_t *range_info)
+ range_id_t* range_info)
{
return(m_ds_mrr.dsmrr_next(range_info));
}
@@ -23706,17 +24192,16 @@ innobase_index_cond(
/*================*/
void* file) /*!< in/out: pointer to ha_innobase */
{
- return handler_index_cond_check(file);
+ return handler_index_cond_check(file);
}
-
+#ifdef MYSQL_VIRTUAL_COLUMNS
/** Get the computed value by supplying the base column values.
@param[in,out] table the table whose virtual column template to be built */
void
innobase_init_vc_templ(
dict_table_t* table)
{
- THD* thd = current_thd;
char dbname[MAX_DATABASE_NAME_LEN + 1];
char tbname[MAX_TABLE_NAME_LEN + 1];
char* name = table->name.m_name;
@@ -23725,12 +24210,10 @@ innobase_init_vc_templ(
char t_dbname[MAX_DATABASE_NAME_LEN + 1];
char t_tbname[MAX_TABLE_NAME_LEN + 1];
- /* Acquire innobase_share_mutex to see if table->vc_templ
- is assigned with its counter part in the share structure */
- mysql_mutex_lock(&innobase_share_mutex);
+ mutex_enter(&dict_sys->mutex);
- if (table->vc_templ) {
- mysql_mutex_unlock(&innobase_share_mutex);
+ if (table->vc_templ != NULL) {
+ mutex_exit(&dict_sys->mutex);
return;
}
@@ -23753,8 +24236,8 @@ innobase_init_vc_templ(
tbnamelen = is_part - tbname;
}
- table->vc_templ = static_cast<innodb_col_templ_t*>(
- ut_zalloc_nokey(sizeof *(table->vc_templ)));
+ table->vc_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
+ table->vc_templ->vtempl = NULL;
dbnamelen = filename_to_tablename(dbname, t_dbname,
MAX_DATABASE_NAME_LEN + 1);
@@ -23772,19 +24255,103 @@ innobase_init_vc_templ(
static_cast<void*>(table));
ut_ad(!ret);
*/
- table->vc_templ_purge = true;
- mysql_mutex_unlock(&innobase_share_mutex);
+ mutex_exit(&dict_sys->mutex);
+}
+
+/** Change dbname and table name in table->vc_templ.
+@param[in,out] table the table whose virtual column template
+dbname and tbname to be renamed. */
+void
+innobase_rename_vc_templ(
+ dict_table_t* table)
+{
+ char dbname[MAX_DATABASE_NAME_LEN + 1];
+ char tbname[MAX_DATABASE_NAME_LEN + 1];
+ char* name = table->name.m_name;
+ ulint dbnamelen = dict_get_db_name_len(name);
+ ulint tbnamelen = strlen(name) - dbnamelen - 1;
+ char t_dbname[MAX_DATABASE_NAME_LEN + 1];
+ char t_tbname[MAX_TABLE_NAME_LEN + 1];
+
+ strncpy(dbname, name, dbnamelen);
+ dbname[dbnamelen] = 0;
+ strncpy(tbname, name + dbnamelen + 1, tbnamelen);
+ tbname[tbnamelen] =0;
+
+ /* For partition table, remove the partition name and use the
+ "main" table name to build the template */
+#ifdef _WIN32
+ char* is_part = strstr(tbname, "#p#");
+#else
+ char* is_part = strstr(tbname, "#P#");
+#endif /* _WIN32 */
+
+ if (is_part != NULL) {
+ *is_part = '\0';
+ tbnamelen = is_part - tbname;
+ }
+
+ dbnamelen = filename_to_tablename(dbname, t_dbname,
+ MAX_DATABASE_NAME_LEN + 1);
+ tbnamelen = filename_to_tablename(tbname, t_tbname,
+ MAX_TABLE_NAME_LEN + 1);
+
+ table->vc_templ->db_name = t_dbname;
+ table->vc_templ->tb_name = t_tbname;
+}
+
+/** Get the updated parent field value from the update vector for the
+given col_no.
+@param[in] foreign foreign key information
+@param[in] update updated parent vector.
+@param[in] col_no column position of the table
+@return updated field from the parent update vector, else NULL */
+static
+dfield_t*
+innobase_get_field_from_update_vector(
+ dict_foreign_t* foreign,
+ upd_t* update,
+ ulint col_no)
+{
+ dict_table_t* parent_table = foreign->referenced_table;
+ dict_index_t* parent_index = foreign->referenced_index;
+ ulint parent_field_no;
+ ulint parent_col_no;
+ ulint prefix_col_no;
+
+ for (ulint i = 0; i < foreign->n_fields; i++) {
+
+ parent_col_no = dict_index_get_nth_col_no(parent_index, i);
+ parent_field_no = dict_table_get_nth_col_pos(
+ parent_table, parent_col_no, &prefix_col_no);
+
+ for (ulint j = 0; j < update->n_fields; j++) {
+ upd_field_t* parent_ufield
+ = &update->fields[j];
+
+ if (parent_ufield->field_no == parent_field_no
+ && parent_col_no == col_no) {
+ return(&parent_ufield->new_val);
+ }
+ }
+ }
+
+ return (NULL);
}
/** Get the computed value by supplying the base column values.
@param[in,out] row the data row
@param[in] col virtual column
@param[in] index index
-@param[in,out] my_rec mysql record to store the data
@param[in,out] local_heap heap memory for processing large data etc.
@param[in,out] heap memory heap that copies the actual index row
@param[in] ifield index field
-@param[in] in_purge whether this is called by purge
+@param[in] thd MySQL thread handle
+@param[in,out] mysql_table mysql table object
+@param[in] old_table during ALTER TABLE, this is the old table
+ or NULL.
+@param[in] parent_update update vector for the parent row
+@param[in] foreign foreign key information
@return the field filled with computed value, or NULL if just want
to store the value in passed in "my_rec" */
dfield_t*
@@ -23792,11 +24359,14 @@ innobase_get_computed_value(
const dtuple_t* row,
const dict_v_col_t* col,
const dict_index_t* index,
- byte* my_rec,
mem_heap_t** local_heap,
mem_heap_t* heap,
const dict_field_t* ifield,
- bool in_purge)
+ THD* thd,
+ TABLE* mysql_table,
+ const dict_table_t* old_table,
+ upd_t* parent_update,
+ dict_foreign_t* foreign)
{
byte rec_buf1[REC_VERSION_56_MAX_INDEX_COL_LEN];
byte rec_buf2[REC_VERSION_56_MAX_INDEX_COL_LEN];
@@ -23804,48 +24374,53 @@ innobase_get_computed_value(
byte* buf;
dfield_t* field;
ulint len;
- const page_size_t page_size = dict_table_page_size(index->table);
+
+ const page_size_t page_size = (old_table == NULL)
+ ? dict_table_page_size(index->table)
+ : dict_table_page_size(old_table);
+
ulint ret = 0;
ut_ad(index->table->vc_templ);
+ ut_ad(thd != NULL);
const mysql_row_templ_t*
vctempl = index->table->vc_templ->vtempl[
index->table->vc_templ->n_col + col->v_pos];
+
if (!heap || index->table->vc_templ->rec_len
>= REC_VERSION_56_MAX_INDEX_COL_LEN) {
if (*local_heap == NULL) {
*local_heap = mem_heap_create(UNIV_PAGE_SIZE);
}
- if (!my_rec) {
- mysql_rec = static_cast<byte*>(mem_heap_alloc(
- *local_heap, index->table->vc_templ->rec_len));
- } else {
- mysql_rec = my_rec;
- }
-
+ mysql_rec = static_cast<byte*>(mem_heap_alloc(
+ *local_heap, index->table->vc_templ->rec_len));
buf = static_cast<byte*>(mem_heap_alloc(
*local_heap, index->table->vc_templ->rec_len));
} else {
- if (!my_rec) {
- mysql_rec = rec_buf1;
- } else {
- mysql_rec = my_rec;
- }
-
+ mysql_rec = rec_buf1;
buf = rec_buf2;
}
for (ulint i = 0; i < col->num_base; i++) {
dict_col_t* base_col = col->base_col[i];
- const dfield_t* row_field;
+ const dfield_t* row_field = NULL;
ulint col_no = base_col->ind;
const mysql_row_templ_t* templ
= index->table->vc_templ->vtempl[col_no];
const byte* data;
- row_field = dtuple_get_nth_field(row, col_no);
+ if (parent_update != NULL) {
+ /** Get the updated field from update vector
+ of the parent table. */
+ row_field = innobase_get_field_from_update_vector(
+ foreign, parent_update, col_no);
+ }
+
+ if (row_field == NULL) {
+ row_field = dtuple_get_nth_field(row, col_no);
+ }
data = static_cast<const byte*>(row_field->data);
len = row_field->len;
@@ -23888,17 +24463,27 @@ innobase_get_computed_value(
/* Bitmap for specifying which virtual columns the server
should evaluate */
- MY_BITMAP column_map;
- my_bitmap_map col_map_storage[bitmap_buffer_size(REC_MAX_N_FIELDS)];
+ MY_BITMAP column_map;
+ my_bitmap_map col_map_storage[bitmap_buffer_size(REC_MAX_N_FIELDS)];
+
bitmap_init(&column_map, col_map_storage, REC_MAX_N_FIELDS, false);
/* Specify the column the server should evaluate */
bitmap_set_bit(&column_map, col->m_col.ind);
- if (in_purge) {
+ if (mysql_table == NULL) {
if (vctempl->type == DATA_BLOB) {
- ulint max_len = DICT_MAX_FIELD_LEN_BY_FORMAT(
- index->table) + 1;
+ ulint max_len;
+
+ if (vctempl->mysql_col_len - 8 == 1) {
+ /* This is for TINYBLOB only, which needs
+ only 1 byte, other BLOBs won't be affected */
+ max_len = 255;
+ } else {
+ max_len = DICT_MAX_FIELD_LEN_BY_FORMAT(
+ index->table) + 1;
+ }
+
byte* blob_mem = static_cast<byte*>(
mem_heap_alloc(heap, max_len));
@@ -23907,31 +24492,28 @@ innobase_get_computed_value(
vctempl->mysql_col_len, blob_mem, max_len);
}
- /* JAN: TODO: MySQL 5.7
- ret = handler::my_eval_gcolumn_expr(
- current_thd, false, index->table->vc_templ->db_name,
- index->table->vc_templ->tb_name, &column_map,
+ ret = handler::my_eval_gcolumn_expr_with_open(
+ thd, index->table->vc_templ->db_name.c_str(),
+ index->table->vc_templ->tb_name.c_str(), &column_map,
(uchar *)mysql_rec);
- */
} else {
- /* JAN: TODO: MySQL 5.7
ret = handler::my_eval_gcolumn_expr(
- current_thd, index->table->vc_templ->db_name,
- index->table->vc_templ->tb_name, &column_map,
+ thd, mysql_table, &column_map,
(uchar *)mysql_rec);
- */
}
if (ret != 0) {
+#ifdef INNODB_VIRTUAL_DEBUG
ib::warn() << "Compute virtual column values failed ";
fputs("InnoDB: Cannot compute value for following record ",
stderr);
dtuple_print(stderr, row);
+#endif /* INNODB_VIRTUAL_DEBUG */
return(NULL);
}
/* we just want to store the data in passed in MySQL record */
- if (my_rec || ret != 0) {
+ if (ret != 0) {
return(NULL);
}
@@ -23974,6 +24556,7 @@ innobase_get_computed_value(
return(field);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/** Attempt to push down an index condition.
@param[in] keyno MySQL key number
@@ -24032,10 +24615,10 @@ ib_senderrf(
switch (level) {
case IB_LOG_LEVEL_INFO:
- l = ME_JUST_INFO;
+ l = ME_JUST_INFO;
break;
case IB_LOG_LEVEL_WARN:
- l = ME_JUST_WARNING;
+ l = ME_JUST_WARNING;
break;
case IB_LOG_LEVEL_ERROR:
sd_notifyf(0, "STATUS=InnoDB: Error: %s", str);
@@ -24050,7 +24633,7 @@ ib_senderrf(
break;
}
- my_printv_error(code, format, MYF(l), args);
+ my_printv_error(code, format, MYF(l), args);
va_end(args);
free(str);
@@ -24221,6 +24804,97 @@ ib_warn_row_too_big(const dict_table_t* table)
, prefix ? DICT_MAX_FIXED_COL_LEN : 0);
}
+/** Validate the requested buffer pool size. Also, reserve the necessary
+memory needed for buffer pool resize.
+@param[in] thd thread handle
+@param[in] var pointer to system variable
+@param[out] save immediate result for update function
+@param[in] value incoming string
+@return 0 on success, 1 on failure.
+*/
+static
+int
+innodb_buffer_pool_size_validate(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* save,
+ struct st_mysql_value* value)
+{
+ longlong intbuf;
+
+
+ value->val_int(value, &intbuf);
+
+ if (!srv_was_started) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_ARGUMENTS,
+ "Cannot update innodb_buffer_pool_size,"
+ " because InnoDB is not started.");
+ return(1);
+ }
+
+#ifdef UNIV_DEBUG
+ if (buf_disable_resize_buffer_pool_debug == TRUE) {
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_ARGUMENTS,
+ "Cannot update innodb_buffer_pool_size,"
+ " because innodb_disable_resize_buffer_pool_debug"
+ " is set.");
+ ib::warn() << "Cannot update innodb_buffer_pool_size,"
+ " because innodb_disable_resize_buffer_pool_debug"
+ " is set.";
+ return(1);
+ }
+#endif /* UNIV_DEBUG */
+
+
+ buf_pool_mutex_enter_all();
+
+ if (srv_buf_pool_old_size != srv_buf_pool_size) {
+ buf_pool_mutex_exit_all();
+ my_error(ER_BUFPOOL_RESIZE_INPROGRESS, MYF(0));
+ return(1);
+ }
+
+ if (srv_buf_pool_instances > 1 && intbuf < BUF_POOL_SIZE_THRESHOLD) {
+ buf_pool_mutex_exit_all();
+
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_WRONG_ARGUMENTS,
+ "Cannot update innodb_buffer_pool_size"
+ " to less than 1GB if"
+ " innodb_buffer_pool_instances > 1.");
+ return(1);
+ }
+
+ ulint requested_buf_pool_size
+ = buf_pool_size_align(static_cast<ulint>(intbuf));
+
+ *static_cast<longlong*>(save) = requested_buf_pool_size;
+
+ if (srv_buf_pool_size == requested_buf_pool_size) {
+ buf_pool_mutex_exit_all();
+ /* nothing to do */
+ return(0);
+ }
+
+ srv_buf_pool_size = requested_buf_pool_size;
+ buf_pool_mutex_exit_all();
+
+ if (intbuf != static_cast<longlong>(requested_buf_pool_size)) {
+ char buf[64];
+ int len = 64;
+ value->val_str(value, buf, &len);
+ push_warning_printf(thd, Sql_condition::WARN_LEVEL_WARN,
+ ER_TRUNCATED_WRONG_VALUE,
+ "Truncated incorrect %-.32s value: '%-.128s'",
+ mysql_sysvar_buffer_pool_size.name,
+ value->val_str(value, buf, &len));
+ }
+
+ return(0);
+}
+
/*************************************************************//**
Check for a valid value of innobase_compression_algorithm.
@return 0 for valid innodb_compression_algorithm. */
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index b2696751be5..312584d5a0e 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -27,11 +27,15 @@ extern const char innobase_index_reserve_name[];
to explicitly create a file_per_table tablespace for the table. */
extern const char reserved_file_per_table_space_name[];
-/* "innodb_system" tablespace name is reserved by InnoDB for the system tablespace
-which uses space_id 0 and stores extra types of system pages like UNDO
-and doublewrite. */
+/* "innodb_system" tablespace name is reserved by InnoDB for the
+system tablespace which uses space_id 0 and stores extra types of
+system pages like UNDO and doublewrite. */
extern const char reserved_system_space_name[];
+/* "innodb_temporary" tablespace name is reserved by InnoDB for the
+predefined shared temporary tablespace. */
+extern const char reserved_temporary_space_name[];
+
/* Structure defines translation table between mysql index and InnoDB
index structures */
struct innodb_idx_translate_t {
@@ -46,38 +50,9 @@ struct innodb_idx_translate_t {
array index */
};
-
-/** Structure defines template related to virtual columns and
-their base columns */
-struct innodb_col_templ_t {
- /** number of regular columns */
- ulint n_col;
-
- /** number of virtual columns */
- ulint n_v_col;
-
- /** array of templates for virtual col and their base columns */
- mysql_row_templ_t** vtempl;
-
- /** table's database name */
- char db_name[MAX_DATABASE_NAME_LEN];
-
- /** table name */
- char tb_name[MAX_TABLE_NAME_LEN];
-
- /** share->table_name */
- char share_name[MAX_DATABASE_NAME_LEN
- + MAX_TABLE_NAME_LEN];
-
- /** MySQL record length */
- ulint rec_len;
-
- /** default column value if any */
- const byte* default_rec;
-};
-
/** InnoDB table share */
typedef struct st_innobase_share {
+ THR_LOCK lock;
const char* table_name; /*!< InnoDB table name */
uint use_count; /*!< reference count,
incremented in get_share()
@@ -88,9 +63,6 @@ typedef struct st_innobase_share {
innodb_idx_translate_t
idx_trans_tbl; /*!< index translation table between
MySQL and InnoDB */
- innodb_col_templ_t
- s_templ; /*!< table virtual column template
- info */
} INNOBASE_SHARE;
/** Prebuilt structures in an InnoDB table handle used within MySQL */
@@ -112,39 +84,15 @@ struct ha_table_option_struct
uint encryption; /*!< DEFAULT, ON, OFF */
ulonglong encryption_key_id; /*!< encryption key id */
};
-
/* JAN: TODO: MySQL 5.7 handler.h */
struct st_handler_tablename
{
const char *db;
const char *tablename;
};
-
/** The class defining a handle to an Innodb table */
class ha_innobase: public handler
{
- ha_statistics* ha_partition_stats; /*!< stats of the partition owner
- handler (if there is one) */
- uint store_key_val_for_row(uint keynr, char* buff, uint buff_len,
- const uchar* record);
- inline void update_thd(THD* thd);
- void update_thd();
- int change_active_index(uint keynr);
- int general_fetch(uchar* buf, uint direction, uint match_mode);
- dberr_t innobase_lock_autoinc();
- ulonglong innobase_peek_autoinc();
- dberr_t innobase_set_max_autoinc(ulonglong auto_inc);
- dberr_t innobase_reset_autoinc(ulonglong auto_inc);
- dberr_t innobase_get_autoinc(ulonglong* value);
- void innobase_initialize_autoinc();
- dict_index_t* innobase_get_index(uint keynr);
-
-#ifdef WITH_WSREP
- int wsrep_append_keys(THD *thd, bool shared,
- const uchar* record0, const uchar* record1);
-#endif
-
- /* Init values for the class: */
public:
ha_innobase(handlerton* hton, TABLE_SHARE* table_arg);
~ha_innobase();
@@ -154,13 +102,21 @@ public:
enum row_type get_row_type() const;
const char* table_type() const;
+
const char* index_type(uint key_number);
+
const char** bas_ext() const;
+
Table_flags table_flags() const;
+
ulong index_flags(uint idx, uint part, bool all_parts) const;
+
uint max_supported_keys() const;
+
uint max_supported_key_length() const;
+
uint max_supported_key_part_length() const;
+
const key_map* keys_to_use_for_scanning();
/** Opens dictionary table object using table name. For partition, we need to
@@ -171,136 +127,192 @@ public:
@param[in] is_partition if this is a partition of a table
@param[in] ignore_err error to ignore for loading dictionary object
@return dictionary table object or NULL if not found */
- static dict_table_t* open_dict_table(
- const char* table_name,
- const char* norm_name,
- bool is_partition,
- dict_err_ignore_t ignore_err);
+ static dict_table_t* open_dict_table(
+ const char* table_name,
+ const char* norm_name,
+ bool is_partition,
+ dict_err_ignore_t ignore_err);
int open(const char *name, int mode, uint test_if_locked);
+
handler* clone(const char *name, MEM_ROOT *mem_root);
+
int close(void);
+
double scan_time();
+
double read_time(uint index, uint ranges, ha_rows rows);
+
longlong get_memory_buffer_size() const;
int delete_all_rows();
int write_row(uchar * buf);
+
int update_row(const uchar * old_data, uchar * new_data);
+
int delete_row(const uchar * buf);
+
bool was_semi_consistent_read();
+
void try_semi_consistent_read(bool yes);
+
void unlock_row();
int index_init(uint index, bool sorted);
+
int index_end();
- int index_read(uchar * buf, const uchar * key,
- uint key_len, enum ha_rkey_function find_flag);
- int index_read_idx(uchar * buf, uint index, const uchar * key,
- uint key_len, enum ha_rkey_function find_flag);
+
+ int index_read(
+ uchar* buf,
+ const uchar* key,
+ uint key_len,
+ ha_rkey_function find_flag);
+
int index_read_last(uchar * buf, const uchar * key, uint key_len);
+
int index_next(uchar * buf);
+
int index_next_same(uchar * buf, const uchar *key, uint keylen);
+
int index_prev(uchar * buf);
+
int index_first(uchar * buf);
+
int index_last(uchar * buf);
int rnd_init(bool scan);
+
int rnd_end();
+
int rnd_next(uchar *buf);
+
int rnd_pos(uchar * buf, uchar *pos);
int ft_init();
+
void ft_end();
- FT_INFO *ft_init_ext(uint flags, uint inx, String* key);
- int ft_read(uchar* buf);
- FT_INFO *ft_init_ext_with_hints(
+ FT_INFO* ft_init_ext(uint flags, uint inx, String* key);
+
+ FT_INFO* ft_init_ext_with_hints(
uint inx,
String* key,
void* hints);
- /* JAN: TODO: MySQL 5.6
- Ft_hints* hints);
- */
+ //Ft_hints* hints);
+
+ int ft_read(uchar* buf);
int enable_indexes(uint mode);
int disable_indexes(uint mode);
void position(const uchar *record);
+
int info(uint);
+
int analyze(THD* thd,HA_CHECK_OPT* check_opt);
+
int optimize(THD* thd,HA_CHECK_OPT* check_opt);
+
int discard_or_import_tablespace(my_bool discard);
- int extra(enum ha_extra_function operation);
+
+ int extra(ha_extra_function operation);
+
int reset();
+
int external_lock(THD *thd, int lock_type);
- int transactional_table_lock(THD *thd, int lock_type);
+
int start_stmt(THD *thd, thr_lock_type lock_type);
+
void position(uchar *record);
- ha_rows records_in_range(uint inx, key_range *min_key, key_range
- *max_key);
+
+ // MySQL 5.7 Select count optimization
+ // int records(ha_rows* num_rows);
+
+ ha_rows records_in_range(
+ uint inx,
+ key_range* min_key,
+ key_range* max_key);
+
ha_rows estimate_rows_upper_bound();
// JAN: TODO: MySQL 5.7
// int records(ha_rows* num_rows);
void update_create_info(HA_CREATE_INFO* create_info);
- int parse_table_name(const char*name,
- HA_CREATE_INFO* create_info,
- ulint flags,
- ulint flags2,
- char* norm_name,
- char* temp_path,
- char* remote_path);
+
+ int create(
+ const char* name,
+ TABLE* form,
+ HA_CREATE_INFO* create_info);
+
const char* check_table_options(THD *thd, TABLE* table,
HA_CREATE_INFO* create_info, const bool use_tablespace, const ulint file_format);
- int create(const char *name, register TABLE *form,
- HA_CREATE_INFO *create_info);
+
int truncate();
+
int delete_table(const char *name);
+
int rename_table(const char* from, const char* to);
int defragment_table(const char* name, const char* index_name,
bool async);
int check(THD* thd, HA_CHECK_OPT* check_opt);
char* update_table_comment(const char* comment);
+
char* get_foreign_key_create_info();
+
int get_foreign_key_list(THD *thd, List<FOREIGN_KEY_INFO> *f_key_list);
- int get_parent_foreign_key_list(THD *thd,
- List<FOREIGN_KEY_INFO> *f_key_list);
+
+ int get_parent_foreign_key_list(
+ THD* thd,
+ List<FOREIGN_KEY_INFO>* f_key_list);
int get_cascade_foreign_key_table_list(
THD* thd,
List<st_handler_tablename>* fk_table_list);
+
bool can_switch_engines();
+
uint referenced_by_foreign_key();
+
void free_foreign_key_create_info(char* str);
- THR_LOCK_DATA **store_lock(THD *thd, THR_LOCK_DATA **to,
- enum thr_lock_type lock_type);
+
+ //uint lock_count(void) const;
+
+ THR_LOCK_DATA** store_lock(
+ THD* thd,
+ THR_LOCK_DATA** to,
+ thr_lock_type lock_type);
+
void init_table_handle_for_HANDLER();
- virtual void get_auto_increment(ulonglong offset, ulonglong increment,
- ulonglong nb_desired_values,
- ulonglong *first_value,
- ulonglong *nb_reserved_values);
- int reset_auto_increment(ulonglong value);
- uint lock_count(void) const;
+ virtual void get_auto_increment(
+ ulonglong offset,
+ ulonglong increment,
+ ulonglong nb_desired_values,
+ ulonglong* first_value,
+ ulonglong* nb_reserved_values);
+ int reset_auto_increment(ulonglong value);
virtual bool get_error_message(int error, String *buf);
+
virtual bool get_foreign_dup_key(char*, uint, char*, uint);
+
uint8 table_cache_type();
/**
Ask handler about permission to cache table during query registration
*/
- my_bool register_query_cache_table(THD *thd, char *table_key,
- uint key_length,
- qc_engine_callback *call_back,
- ulonglong *engine_data);
- static const char *get_mysql_bin_log_name();
- static ulonglong get_mysql_bin_log_pos();
+ my_bool register_query_cache_table(
+ THD* thd,
+ char* table_key,
+ uint key_length,
+ qc_engine_callback* call_back,
+ ulonglong* engine_data);
+
bool primary_key_is_clustered();
- int cmp_ref(const uchar *ref1, const uchar *ref2);
+
+ int cmp_ref(const uchar* ref1, const uchar* ref2);
/** On-line ALTER TABLE interface @see handler0alter.cc @{ */
@@ -371,87 +383,74 @@ public:
Alter_inplace_info* ha_alter_info,
bool commit);
/** @} */
- void set_partition_owner_stats(ha_statistics *stats);
-
- bool check_if_incompatible_data(HA_CREATE_INFO *info,
- uint table_changes);
- bool check_if_supported_virtual_columns(void) { return TRUE; }
-
-private:
- /** Builds a 'template' to the prebuilt struct.
-
- The template is used in fast retrieval of just those column
- values MySQL needs in its processing.
- @param whole_row true if access is needed to a whole row,
- false if accessing individual fields is enough */
- void build_template(bool whole_row);
- /** Resets a query execution 'template'.
- @see build_template() */
- inline void reset_template();
- int info_low(uint, bool);
-
- /** Write Row Interface optimized for Intrinsic table. */
- int intrinsic_table_write_row(uchar* record);
+ bool check_if_incompatible_data(
+ HA_CREATE_INFO* info,
+ uint table_changes);
-public:
/** @name Multi Range Read interface @{ */
+
/** Initialize multi range read @see DsMrr_impl::dsmrr_init
- * @param seq
- * @param seq_init_param
- * @param n_ranges
- * @param mode
- * @param buf
- */
- int multi_range_read_init(RANGE_SEQ_IF* seq,
- void* seq_init_param,
- uint n_ranges, uint mode,
- HANDLER_BUFFER* buf);
+ @param seq
+ @param seq_init_param
+ @param n_ranges
+ @param mode
+ @param buf */
+ int multi_range_read_init(
+ RANGE_SEQ_IF* seq,
+ void* seq_init_param,
+ uint n_ranges,
+ uint mode,
+ HANDLER_BUFFER* buf);
+
/** Process next multi range read @see DsMrr_impl::dsmrr_next
- * @param range_info
- */
- int multi_range_read_next(range_id_t *range_info);
+ @param range_info */
+ int multi_range_read_next(range_id_t *range_info);
+
/** Initialize multi range read and get information.
- * @see ha_myisam::multi_range_read_info_const
- * @see DsMrr_impl::dsmrr_info_const
- * @param keyno
- * @param seq
- * @param seq_init_param
- * @param n_ranges
- * @param bufsz
- * @param flags
- * @param cost
- */
- ha_rows multi_range_read_info_const(uint keyno, RANGE_SEQ_IF* seq,
- void* seq_init_param,
- uint n_ranges, uint* bufsz,
- uint* flags, Cost_estimate* cost);
+ @see ha_myisam::multi_range_read_info_const
+ @see DsMrr_impl::dsmrr_info_const
+ @param keyno
+ @param seq
+ @param seq_init_param
+ @param n_ranges
+ @param bufsz
+ @param flags
+ @param cost */
+ ha_rows multi_range_read_info_const(
+ uint keyno,
+ RANGE_SEQ_IF* seq,
+ void* seq_init_param,
+ uint n_ranges,
+ uint* bufsz,
+ uint* flags,
+ Cost_estimate* cost);
+
/** Initialize multi range read and get information.
- * @see DsMrr_impl::dsmrr_info
- * @param keyno
- * @param seq
- * @param seq_init_param
- * @param n_ranges
- * @param bufsz
- * @param flags
- * @param cost
- */
+ @see DsMrr_impl::dsmrr_info
+ @param keyno
+ @param seq
+ @param seq_init_param
+ @param n_ranges
+ @param bufsz
+ @param flags
+ @param cost */
ha_rows multi_range_read_info(uint keyno, uint n_ranges, uint keys,
uint key_parts, uint* bufsz, uint* flags,
Cost_estimate* cost);
- int multi_range_read_explain_info(uint mrr_mode,
- char *str, size_t size);
+ int multi_range_read_explain_info(uint mrr_mode,
+ char *str, size_t size);
/** Attempt to push down an index condition.
- * @param[in] keyno MySQL key number
- * @param[in] idx_cond Index condition to be checked
- * @return idx_cond if pushed; NULL if not pushed
- */
- class Item* idx_cond_push(uint keyno, class Item* idx_cond);
+ @param[in] keyno MySQL key number
+ @param[in] idx_cond Index condition to be checked
+ @return idx_cond if pushed; NULL if not pushed */
+ Item* idx_cond_push(uint keyno, Item* idx_cond);
+ /* @} */
- /* An helper function for index_cond_func_innodb: */
- bool is_thd_killed();
+ /* An helper function for index_cond_func_innodb: */
+ bool is_thd_killed();
protected:
@@ -461,6 +460,42 @@ protected:
doesn't give any clue that it is called at the end of a statement. */
int end_stmt();
+ dberr_t innobase_get_autoinc(ulonglong* value);
+ void innobase_initialize_autoinc();
+ dberr_t innobase_lock_autoinc();
+ ulonglong innobase_peek_autoinc();
+ dberr_t innobase_set_max_autoinc(ulonglong auto_inc);
+ dberr_t innobase_reset_autoinc(ulonglong auto_inc);
+
+ /** Resets a query execution 'template'.
+ @see build_template() */
+ void reset_template();
+
+ /** Write Row Interface optimized for Intrinsic table. */
+ int intrinsic_table_write_row(uchar* record);
+
+protected:
+ inline void update_thd(THD* thd);
+ void update_thd();
+
+ int general_fetch(uchar* buf, uint direction, uint match_mode);
+ int change_active_index(uint keynr);
+ dict_index_t* innobase_get_index(uint keynr);
+
+#ifdef WITH_WSREP
+ int wsrep_append_keys(THD *thd, bool shared,
+ const uchar* record0, const uchar* record1);
+#endif
+ /** Builds a 'template' to the prebuilt struct.
+
+ The template is used in fast retrieval of just those column
+ values MySQL needs in its processing.
+ @param whole_row true if access is needed to a whole row,
+ false if accessing individual fields is enough */
+ void build_template(bool whole_row);
+
+ virtual int info_low(uint, bool);
+
/** The multi range read session object */
DsMrr_impl m_ds_mrr;
@@ -475,6 +510,8 @@ protected:
this is set in external_lock function */
THD* m_user_thd;
+ THR_LOCK_DATA lock;
+
/** information for MySQL table locking */
INNOBASE_SHARE* m_share;
@@ -514,70 +551,51 @@ the definitions are bracketed with #ifdef INNODB_COMPATIBILITY_HOOKS */
#error InnoDB needs MySQL to be built with #define INNODB_COMPATIBILITY_HOOKS
#endif
+LEX_STRING* thd_query_string(MYSQL_THD thd);
+size_t thd_query_safe(MYSQL_THD thd, char *buf, size_t buflen);
+
extern "C" {
struct charset_info_st *thd_charset(MYSQL_THD thd);
-LEX_STRING* thd_query_string(MYSQL_THD thd);
-/**
- Check if a user thread is a replication slave thread
- @param thd user thread
- @retval 0 the user thread is not a replication slave thread
- @retval 1 the user thread is a replication slave thread
-*/
+/** Check if a user thread is a replication slave thread
+@param thd user thread
+@retval 0 the user thread is not a replication slave thread
+@retval 1 the user thread is a replication slave thread */
int thd_slave_thread(const MYSQL_THD thd);
-/**
- Check if a user thread is running a non-transactional update
- @param thd user thread
- @retval 0 the user thread is not running a non-transactional update
- @retval 1 the user thread is running a non-transactional update
-*/
+/** Check if a user thread is running a non-transactional update
+@param thd user thread
+@retval 0 the user thread is not running a non-transactional update
+@retval 1 the user thread is running a non-transactional update */
int thd_non_transactional_update(const MYSQL_THD thd);
-/**
- Get the user thread's binary logging format
- @param thd user thread
- @return Value to be used as index into the binlog_format_names array
-*/
+/** Get the user thread's binary logging format
+@param thd user thread
+@return Value to be used as index into the binlog_format_names array */
int thd_binlog_format(const MYSQL_THD thd);
-/**
- Mark transaction to rollback and mark error as fatal to a sub-statement.
- @param thd Thread handle
- @param all TRUE <=> rollback main transaction.
-*/
-void thd_mark_transaction_to_rollback(MYSQL_THD thd, bool all);
-
-/**
- Check if binary logging is filtered for thread's current db.
- @param thd Thread handle
- @retval 1 the query is not filtered, 0 otherwise.
-*/
+/** Check if binary logging is filtered for thread's current db.
+@param thd Thread handle
+@retval 1 the query is not filtered, 0 otherwise. */
bool thd_binlog_filter_ok(const MYSQL_THD thd);
-/**
- Check if the query may generate row changes which
- may end up in the binary.
- @param thd Thread handle
- @return 1 the query may generate row changes, 0 otherwise.
+/** Check if the query may generate row changes which may end up in the binary.
+@param thd Thread handle
+@retval 1 the query may generate row changes, 0 otherwise.
*/
bool thd_sqlcom_can_generate_row_events(const MYSQL_THD thd);
-/**
- Gets information on the durability property requested by
- a thread.
- @param thd Thread handle
- @return a durability property.
-*/
-enum durability_properties thd_get_durability_property(const MYSQL_THD thd);
+/** Gets information on the durability property requested by a thread.
+@param thd Thread handle
+@return a durability property. */
+durability_properties thd_get_durability_property(const MYSQL_THD thd);
/** Is strict sql_mode set.
-@param thd Thread object
-@return True if sql_mode has strict mode (all or trans), false otherwise.
-*/
-bool thd_is_strict_mode(const MYSQL_THD thd)
-__attribute__((nonnull));
+@param thd Thread object
+@return True if sql_mode has strict mode (all or trans), false otherwise. */
+bool thd_is_strict_mode(const MYSQL_THD thd);
+
} /* extern "C" */
/** Get the file name and position of the MySQL binlog corresponding to the
@@ -657,50 +675,16 @@ innobase_index_name_is_reserved(
created */
ulint num_of_keys) /*!< in: Number of indexes to
be created. */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
extern const char reserved_file_per_table_space_name[];
+
#ifdef WITH_WSREP
//extern "C" int wsrep_trx_is_aborting(void *thd_ptr);
#endif
/** Check if the explicit tablespace targeted is file_per_table.
@param[in] create_info Metadata for the table to create.
-Determines InnoDB table flags.
-@retval true if successful, false if error */
-UNIV_INTERN
-bool
-innobase_table_flags(
-/*=================*/
- const TABLE* form, /*!< in: table */
- const HA_CREATE_INFO* create_info, /*!< in: information
- on table columns and indexes */
- THD* thd, /*!< in: connection */
- bool use_tablespace, /*!< in: whether to create
- outside system tablespace */
- ulint* flags, /*!< out: DICT_TF flags */
- ulint* flags2) /*!< out: DICT_TF2 flags */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/*****************************************************************//**
-Validates the create options. We may build on this function
-in future. For now, it checks two specifiers:
-KEY_BLOCK_SIZE and ROW_FORMAT
-If innodb_strict_mode is not set then this function is a no-op
-@return NULL if valid, string if not. */
-UNIV_INTERN
-const char*
-create_options_are_invalid(
-/*=======================*/
- THD* thd, /*!< in: connection thread. */
- TABLE* form, /*!< in: information on table
- columns and indexes */
- HA_CREATE_INFO* create_info, /*!< in: create info. */
- bool use_tablespace) /*!< in: srv_file_per_table */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/** Check if the explicit tablespace targeted is file_per_table.
-@param[in] create_info Metadata for the table to create.
@return true if the table is intended to use a file_per_table tablespace. */
UNIV_INLINE
bool
@@ -712,18 +696,37 @@ tablespace_is_file_per_table(
reserved_file_per_table_space_name)));
}
-/** Check if table will be put in an existing shared general tablespace.
+/** Check if table will be explicitly put in an existing shared general
+or system tablespace.
@param[in] create_info Metadata for the table to create.
-@return true if the table will use an existing shared general tablespace. */
+@return true if the table will use a shared general or system tablespace. */
UNIV_INLINE
bool
tablespace_is_shared_space(
+const HA_CREATE_INFO* create_info)
+{
+ return(create_info->tablespace != NULL
+ && create_info->tablespace[0] != '\0'
+ && (0 != strcmp(create_info->tablespace,
+ reserved_file_per_table_space_name)));
+}
+
+/** Check if table will be explicitly put in a general tablespace.
+@param[in] create_info Metadata for the table to create.
+@return true if the table will use a general tablespace. */
+UNIV_INLINE
+bool
+tablespace_is_general_space(
const HA_CREATE_INFO* create_info)
{
return(create_info->tablespace != NULL
- && create_info->tablespace[0] != '\0'
- && (0 != strcmp(create_info->tablespace,
- reserved_file_per_table_space_name)));
+ && create_info->tablespace[0] != '\0'
+ && (0 != strcmp(create_info->tablespace,
+ reserved_file_per_table_space_name))
+ && (0 != strcmp(create_info->tablespace,
+ reserved_temporary_space_name))
+ && (0 != strcmp(create_info->tablespace,
+ reserved_system_space_name)));
}
/** Parse hint for table and its indexes, and update the information
@@ -796,6 +799,9 @@ public:
/** Validate TABLESPACE option. */
bool create_option_tablespace_is_valid();
+ /** Validate COMPRESSION option. */
+ bool create_option_compression_is_valid();
+
/** Prepare to create a table. */
int prepare_create_table(const char* name);
@@ -912,7 +918,8 @@ private:
/** Table flags2 */
ulint m_flags2;
};
-/*********************************************************************//**
+
+/**
Retrieve the FTS Relevance Ranking result for doc with doc_id
of prebuilt->fts_doc_id
@return the relevance ranking value */
@@ -934,9 +941,8 @@ innobase_fts_find_ranking(
Free the memory for the FTS handler */
void
innobase_fts_close_ranking(
-/*=======================*/
- FT_INFO* fts_hdl) /*!< in: FTS handler */
- MY_ATTRIBUTE((nonnull));
+ FT_INFO* fts_hdl); /*!< in: FTS handler */
+
/**
Initialize the table FTS stopword list
@return TRUE if success */
@@ -946,7 +952,7 @@ innobase_fts_load_stopword(
dict_table_t* table, /*!< in: Table has the FTS */
trx_t* trx, /*!< in: transaction */
THD* thd) /*!< in: current thread */
- MY_ATTRIBUTE((nonnull(1,3), warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Some defines for innobase_fts_check_doc_id_index() return value */
enum fts_doc_id_index_enum {
@@ -961,7 +967,6 @@ on the Doc ID column.
@return the status of the FTS_DOC_ID index */
fts_doc_id_index_enum
innobase_fts_check_doc_id_index(
-/*============================*/
const dict_table_t* table, /*!< in: table definition */
const TABLE* altered_table, /*!< in: MySQL table
that is being altered */
@@ -976,22 +981,21 @@ on the Doc ID column in MySQL create index definition.
FTS_INCORRECT_DOC_ID_INDEX if the FTS_DOC_ID index is of wrong format */
fts_doc_id_index_enum
innobase_fts_check_doc_id_index_in_def(
-/*===================================*/
ulint n_key, /*!< in: Number of keys */
const KEY* key_info) /*!< in: Key definitions */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
-/***********************************************************************
+/**
@return version of the extended FTS API */
uint
innobase_fts_get_version();
-/***********************************************************************
+/**
@return Which part of the extended FTS API is supported */
ulonglong
innobase_fts_flags();
-/***********************************************************************
+/**
Find and Retrieve the FTS doc_id for the current result row
@return the document ID */
ulonglong
@@ -999,7 +1003,7 @@ innobase_fts_retrieve_docid(
/*========================*/
FT_INFO_EXT* fts_hdl); /*!< in: FTS handler */
-/***********************************************************************
+/**
Find and retrieve the size of the current result
@return number of matching rows */
ulonglong
@@ -1007,50 +1011,54 @@ innobase_fts_count_matches(
/*=======================*/
FT_INFO_EXT* fts_hdl); /*!< in: FTS handler */
-/** "GEN_CLUST_INDEX" is the name reserved for InnoDB default
-system clustered index when there is no primary key. */
-extern const char innobase_index_reserve_name[];
-
-/*********************************************************************//**
+/**
Copy table flags from MySQL's HA_CREATE_INFO into an InnoDB table object.
Those flags are stored in .frm file and end up in the MySQL table object,
but are frequently used inside InnoDB so we keep their copies into the
InnoDB table object. */
-UNIV_INTERN
void
innobase_copy_frm_flags_from_create_info(
-/*=====================================*/
dict_table_t* innodb_table, /*!< in/out: InnoDB table */
const HA_CREATE_INFO* create_info); /*!< in: create info */
-/*********************************************************************//**
+/**
Copy table flags from MySQL's TABLE_SHARE into an InnoDB table object.
Those flags are stored in .frm file and end up in the MySQL table object,
but are frequently used inside InnoDB so we keep their copies into the
InnoDB table object. */
-UNIV_INTERN
void
innobase_copy_frm_flags_from_table_share(
-/*=====================================*/
dict_table_t* innodb_table, /*!< in/out: InnoDB table */
const TABLE_SHARE* table_share); /*!< in: table share */
-/********************************************************************//**
-Helper function to push frm mismatch error to error log and
-if needed to sql-layer. */
-UNIV_INTERN
+/** Set up base columns for virtual column
+@param[in] table the InnoDB table
+@param[in] field MySQL field
+@param[in,out] v_col virtual column to be set up */
void
-ib_push_frm_error(
-/*==============*/
- THD* thd, /*!< in: MySQL thd */
- dict_table_t* ib_table, /*!< in: InnoDB table */
- TABLE* table, /*!< in: MySQL table */
- ulint n_keys, /*!< in: InnoDB #keys */
- bool push_warning); /*!< in: print warning ? */
+innodb_base_col_setup(
+ dict_table_t* table,
+ const Field* field,
+ dict_v_col_t* v_col);
+/** Set up base columns for stored column
+@param[in] table InnoDB table
+@param[in] field MySQL field
+@param[in,out] s_col stored column */
+void
+innodb_base_col_setup_for_stored(
+ const dict_table_t* table,
+ const Field* field,
+ dict_s_col_t* s_col);
+
+/** whether this is a stored column */
+// JAN: TODO: MySQL 5.7 virtual fields
+//#define innobase_is_s_fld(field) ((field)->gcol_info && (field)->stored_in_db)
+#define innobase_is_s_fld(field) (field == NULL)
// JAN: TODO: MySQL 5.7 virtual fields
-// #define innobase_is_v_fld(field) ((field)->gcol_info && !(field)->stored_in_db)
-#define innobase_is_v_fld(field) (false)
+/** whether this is a computed virtual column */
+//#define innobase_is_v_fld(field) ((field)->gcol_info && !(field)->stored_in_db)
+#define innobase_is_v_fld(field) (field == NULL)
/** Release temporary latches.
Call this function when mysqld passes control to the client. That is to
@@ -1133,28 +1141,11 @@ void
innobase_build_v_templ(
const TABLE* table,
const dict_table_t* ib_table,
- innodb_col_templ_t* s_templ,
+ dict_vcol_templ_t* s_templ,
const dict_add_v_col_t* add_v,
bool locked,
const char* share_tbl_name);
-/** Free a virtual template in INNOBASE_SHARE structure
-@param[in,out] share table share holds the template to free */
-void
-free_share_vtemp(
- INNOBASE_SHARE* share);
-
-/** Refresh template for the virtual columns and their base columns if
-the share structure exists
-@param[in] table MySQL TABLE
-@param[in] ib_table InnoDB dict_table_t
-@param[in] table_name table_name used to find the share structure */
-void
-refresh_share_vtempl(
- const TABLE* mysql_table,
- const dict_table_t* ib_table,
- const char* table_name);
-
/** callback used by MySQL server layer to initialized
the table virtual columns' template
@param[in] table MySQL TABLE
@@ -1168,25 +1159,32 @@ innobase_build_v_templ_callback(
the table virtual columns' template */
typedef void (*my_gcolumn_templatecallback_t)(const TABLE*, void*);
-/** Get the computed value by supplying the base column values.
-@param[in,out] table the table whose virtual column template to be built */
-void
-innobase_init_vc_templ(
- dict_table_t* table);
-
-/** Free the virtual column template
-@param[in,out] vc_templ virtual column template */
-void
-free_vc_templ(
- innodb_col_templ_t* vc_templ);
-
-/** Set up base columns for virtual column
-@param[in] table InnoDB table
-@param[in] field MySQL field
-@param[in,out] v_col virtual column */
+/********************************************************************//**
+Helper function to push frm mismatch error to error log and
+if needed to sql-layer. */
+UNIV_INTERN
void
-innodb_base_col_setup(
- dict_table_t* table,
- const Field* field,
- dict_v_col_t* v_col);
+ib_push_frm_error(
+/*==============*/
+ THD* thd, /*!< in: MySQL thd */
+ dict_table_t* ib_table, /*!< in: InnoDB table */
+ TABLE* table, /*!< in: MySQL table */
+ ulint n_keys, /*!< in: InnoDB #keys */
+ bool push_warning); /*!< in: print warning ? */
+/*****************************************************************//**
+Validates the create options. We may build on this function
+in future. For now, it checks two specifiers:
+KEY_BLOCK_SIZE and ROW_FORMAT
+If innodb_strict_mode is not set then this function is a no-op
+@return NULL if valid, string if not. */
+UNIV_INTERN
+const char*
+create_options_are_invalid(
+/*=======================*/
+ THD* thd, /*!< in: connection thread. */
+ TABLE* form, /*!< in: information on table
+ columns and indexes */
+ HA_CREATE_INFO* create_info, /*!< in: create info. */
+ bool use_tablespace) /*!< in: srv_file_per_table */
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
diff --git a/storage/innobase/handler/ha_innopart.cc b/storage/innobase/handler/ha_innopart.cc
index 855090af95d..5fd02dfa016 100644
--- a/storage/innobase/handler/ha_innopart.cc
+++ b/storage/innobase/handler/ha_innopart.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All rights reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -79,8 +79,7 @@ Ha_innopart_share::Ha_innopart_share(
m_tot_parts(),
m_index_count(),
m_ref_count(),
- m_table_share(table_share),
- m_s_templ()
+ m_table_share(table_share)
{}
Ha_innopart_share::~Ha_innopart_share()
@@ -94,11 +93,6 @@ Ha_innopart_share::~Ha_innopart_share()
ut_free(m_index_mapping);
m_index_mapping = NULL;
}
- if (m_s_templ != NULL) {
- free_vc_templ(m_s_templ);
- ut_free(m_s_templ);
- m_s_templ = NULL;
- }
}
/** Fold to lower case if windows or lower_case_table_names == 1.
@@ -229,25 +223,27 @@ Ha_innopart_share::set_v_templ(
dict_table_t* ib_table,
const char* name)
{
-#ifndef DBUG_OFF
- if (m_table_share->tmp_table == NO_TMP_TABLE) {
- mysql_mutex_assert_owner(&m_table_share->LOCK_ha_data);
- }
-#endif /* DBUG_OFF */
+ ut_ad(mutex_own(&dict_sys->mutex));
if (ib_table->n_v_cols > 0) {
- if (!m_s_templ) {
- m_s_templ = static_cast<innodb_col_templ_t*>(
- ut_zalloc_nokey( sizeof *m_s_templ));
- innobase_build_v_templ(table, ib_table,
- m_s_templ, NULL, false, name);
-
- for (ulint i = 0; i < m_tot_parts; i++) {
- m_table_parts[i]->vc_templ = m_s_templ;
+ for (ulint i = 0; i < m_tot_parts; i++) {
+ if (m_table_parts[i]->vc_templ == NULL) {
+ m_table_parts[i]->vc_templ
+ = UT_NEW_NOKEY(dict_vcol_templ_t());
+ m_table_parts[i]->vc_templ->vtempl = NULL;
+ } else if (m_table_parts[i]->get_ref_count() == 1) {
+ /* Clean and refresh the template */
+ dict_free_vc_templ(m_table_parts[i]->vc_templ);
+ m_table_parts[i]->vc_templ->vtempl = NULL;
+ }
+
+ if (m_table_parts[i]->vc_templ->vtempl == NULL) {
+ innobase_build_v_templ(
+ table, ib_table,
+ m_table_parts[i]->vc_templ,
+ NULL, true, name);
}
}
- } else {
- ut_ad(!m_s_templ);
}
}
@@ -467,12 +463,6 @@ Ha_innopart_share::close_table_parts()
m_index_mapping = NULL;
}
- if (m_s_templ != NULL) {
- free_vc_templ(m_s_templ);
- ut_free(m_s_templ);
- m_s_templ = NULL;
- }
-
m_tot_parts = 0;
m_index_count = 0;
}
@@ -1128,10 +1118,13 @@ share_error:
m_prebuilt->default_rec = table->s->default_values;
ut_ad(m_prebuilt->default_rec);
+ DBUG_ASSERT(table != NULL);
+ m_prebuilt->m_mysql_table = table;
+
if (ib_table->n_v_cols > 0) {
- lock_shared_ha_data();
+ mutex_enter(&dict_sys->mutex);
m_part_share->set_v_templ(table, ib_table, name);
- unlock_shared_ha_data();
+ mutex_exit(&dict_sys->mutex);
}
/* Looks like MySQL-3.23 sometimes has primary key number != 0. */
@@ -1763,6 +1756,9 @@ ha_innopart::index_init(
m_prebuilt->m_no_prefetch = true;
}
+ /* For scan across partitions, the keys needs to be materialized */
+ m_prebuilt->m_read_virtual_key = true;
+
error = change_active_index(part_id, keynr);
if (error != 0) {
destroy_record_priority_queue();
@@ -1787,12 +1783,14 @@ ha_innopart::index_end()
if (part_id == MY_BIT_NONE) {
/* Never initialized any index. */
+ active_index = MAX_KEY;
DBUG_RETURN(0);
}
if (m_ordered) {
destroy_record_priority_queue();
m_prebuilt->m_no_prefetch = false;
}
+ m_prebuilt->m_read_virtual_key = false;
DBUG_RETURN(ha_innobase::index_end());
}
@@ -2119,7 +2117,7 @@ ha_innopart::index_next_in_part(
ut_ad(m_ordered_scan_ongoing
|| m_ordered_rec_buffer == NULL
|| m_prebuilt->used_in_HANDLER
- || m_part_info->num_partitions_used() <= 1);
+ || m_part_spec.start_part >= m_part_spec.end_part);
DBUG_RETURN(error);
}
@@ -2182,7 +2180,7 @@ ha_innopart::index_prev_in_part(
ut_ad(m_ordered_scan_ongoing
|| m_ordered_rec_buffer == NULL
|| m_prebuilt->used_in_HANDLER
- || m_part_info->num_partitions_used() <= 1);
+ || m_part_spec.start_part >= m_part_spec.end_part);
return(error);
}
@@ -2553,6 +2551,19 @@ ha_innopart::update_part_elem(
ib_table->tablespace);
}
}
+ else {
+ ut_ad(part_elem->tablespace_name == NULL
+ || 0 == strcmp(part_elem->tablespace_name,
+ "innodb_file_per_table"));
+ if (part_elem->tablespace_name != NULL
+ && 0 != strcmp(part_elem->tablespace_name,
+ "innodb_file_per_table")) {
+
+ /* Update part_elem tablespace to NULL same as in
+ innodb data dictionary ib_table. */
+ part_elem->tablespace_name = NULL;
+ }
+ }
}
/** Update create_info.
@@ -3537,14 +3548,31 @@ ha_innopart::info_low(
checked_sys_tablespace = true;
}
- ulint space = static_cast<ulint>(
+ uintmax_t space =
fsp_get_available_space_in_free_extents(
- ib_table->space));
- if (space == ULINT_UNDEFINED) {
- ut_ad(0);
- avail_space = space;
+ ib_table->space);
+ if (space == UINTMAX_MAX) {
+ THD* thd = ha_thd();
+ const char* table_name
+ = ib_table->name.m_name;
+
+ push_warning_printf(
+ thd,
+ Sql_condition::SL_WARNING,
+ ER_CANT_GET_STAT,
+ "InnoDB: Trying to get the"
+ " free space for partition %s"
+ " but its tablespace has been"
+ " discarded or the .ibd file"
+ " is missing. Setting the free"
+ " space of the partition to"
+ " zero.",
+ ut_get_name(
+ m_prebuilt->trx,
+ table_name).c_str());
} else {
- avail_space += space;
+ avail_space +=
+ static_cast<ulint>(space);
}
}
}
@@ -3598,35 +3626,7 @@ ha_innopart::info_low(
if ((flag & HA_STATUS_NO_LOCK) == 0
&& (flag & HA_STATUS_VARIABLE_EXTRA) != 0
&& srv_force_recovery < SRV_FORCE_NO_IBUF_MERGE) {
-
- if (avail_space == ULINT_UNDEFINED) {
- THD* thd;
- char errbuf[MYSYS_STRERROR_SIZE];
-
- thd = ha_thd();
-
- std::string err_str;
- err_str = "InnoDB: Trying to get"
- " the free space for table ";
- err_str += ut_get_name(m_prebuilt->trx,
- ib_table->name.m_name);
- err_str += " but its tablespace has been"
- " discarded or the .ibd file is"
- " missing. Setting the free space to"
- " zero.";
- push_warning_printf(
- thd,
- Sql_condition::SL_WARNING,
- ER_CANT_GET_STAT,
- err_str.c_str(),
- errno,
- my_strerror(errbuf, sizeof(errbuf),
- errno));
-
- stats.delete_length = 0;
- } else {
- stats.delete_length = avail_space * 1024;
- }
+ stats.delete_length = avail_space * 1024;
}
stats.check_time = 0;
@@ -4085,6 +4085,39 @@ ha_innopart::start_stmt(
return(error);
}
+/** Function to store lock for all partitions in native partitioned table. Also
+look at ha_innobase::store_lock for more details.
+@param[in] thd user thread handle
+@param[in] to pointer to the current element in an array of
+pointers to lock structs
+@param[in] lock_type lock type to store in 'lock'; this may also be
+TL_IGNORE
+@retval to pointer to the current element in the 'to' array */
+THR_LOCK_DATA**
+ha_innopart::store_lock(
+ THD* thd,
+ THR_LOCK_DATA** to,
+ thr_lock_type lock_type)
+{
+ trx_t* trx = m_prebuilt->trx;
+ const uint sql_command = thd_sql_command(thd);
+
+ ha_innobase::store_lock(thd, to, lock_type);
+
+ if (sql_command == SQLCOM_FLUSH
+ && lock_type == TL_READ_NO_INSERT) {
+ for (uint i = 1; i < m_tot_parts; i++) {
+ dict_table_t* table = m_part_share->get_table_part(i);
+
+ dberr_t err = row_quiesce_set_state(
+ table, QUIESCE_START, trx);
+ ut_a(err == DB_SUCCESS || err == DB_UNSUPPORTED);
+ }
+ }
+
+ return to;
+}
+
/** Lock/prepare to lock table.
As MySQL will execute an external lock for every new table it uses when it
starts to process an SQL statement (an exception is when MySQL calls
@@ -4102,8 +4135,6 @@ ha_innopart::external_lock(
int lock_type)
{
int error = 0;
- bool is_quiesce_set = false;
- bool is_quiesce_start = false;
if (m_part_info->get_first_used_partition() == MY_BIT_NONE
&& !(m_mysql_has_locked
@@ -4116,63 +4147,55 @@ ha_innopart::external_lock(
ut_ad(m_mysql_has_locked || lock_type != F_UNLCK);
m_prebuilt->table = m_part_share->get_table_part(0);
- switch (m_prebuilt->table->quiesce) {
- case QUIESCE_START:
- /* Check for FLUSH TABLE t WITH READ LOCK; */
- if (!srv_read_only_mode
- && thd_sql_command(thd) == SQLCOM_FLUSH
- && lock_type == F_RDLCK) {
-
- is_quiesce_set = true;
- is_quiesce_start = true;
- }
- break;
+ error = ha_innobase::external_lock(thd, lock_type);
- case QUIESCE_COMPLETE:
- /* Check for UNLOCK TABLES; implicit or explicit
- or trx interruption. */
- if (m_prebuilt->trx->flush_tables > 0
- && (lock_type == F_UNLCK
- || trx_is_interrupted(m_prebuilt->trx))) {
+ for (uint i = 0; i < m_tot_parts; i++) {
+ dict_table_t* table = m_part_share->get_table_part(i);
- is_quiesce_set = true;
- }
+ switch (table->quiesce) {
+ case QUIESCE_START:
+ /* Check for FLUSH TABLE t WITH READ LOCK */
+ if (!srv_read_only_mode
+ && thd_sql_command(thd) == SQLCOM_FLUSH
+ && lock_type == F_RDLCK) {
- break;
+ ut_ad(table->quiesce == QUIESCE_START);
- case QUIESCE_NONE:
- break;
- default:
- ut_ad(0);
- }
+ row_quiesce_table_start(table,
+ m_prebuilt->trx);
- error = ha_innobase::external_lock(thd, lock_type);
+ /* Use the transaction instance to track
+ UNLOCK TABLES. It can be done via START
+ TRANSACTION; too implicitly. */
- /* FLUSH FOR EXPORT is done above only for the first partition,
- so complete it for all the other partitions. */
- if (is_quiesce_set) {
- for (uint i = 1; i < m_tot_parts; i++) {
- dict_table_t* table = m_part_share->get_table_part(i);
- if (is_quiesce_start) {
- table->quiesce = QUIESCE_START;
- row_quiesce_table_start(table, m_prebuilt->trx);
+ ++m_prebuilt->trx->flush_tables;
+ }
+ break;
- /* Use the transaction instance to track UNLOCK
- TABLES. It can be done via START TRANSACTION;
- too implicitly. */
+ case QUIESCE_COMPLETE:
+ /* Check for UNLOCK TABLES; implicit or explicit
+ or trx interruption. */
+ if (m_prebuilt->trx->flush_tables > 0
+ && (lock_type == F_UNLCK
+ || trx_is_interrupted(m_prebuilt->trx))) {
- ++m_prebuilt->trx->flush_tables;
- } else {
ut_ad(table->quiesce == QUIESCE_COMPLETE);
row_quiesce_table_complete(table,
- m_prebuilt->trx);
+ m_prebuilt->trx);
ut_a(m_prebuilt->trx->flush_tables > 0);
--m_prebuilt->trx->flush_tables;
}
+ break;
+
+ case QUIESCE_NONE:
+ break;
+
+ default:
+ ut_ad(0);
}
- m_prebuilt->table = m_part_share->get_table_part(0);
}
+
ut_ad(!m_auto_increment_lock);
ut_ad(!m_auto_increment_safe_stmt_log_lock);
diff --git a/storage/innobase/handler/ha_innopart.h b/storage/innobase/handler/ha_innopart.h
index 0a6bfe0b2f1..8caa9cdd8d2 100644
--- a/storage/innobase/handler/ha_innopart.h
+++ b/storage/innobase/handler/ha_innopart.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -21,9 +21,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
#ifndef ha_innopart_h
#define ha_innopart_h
-/* JAN: TODO: MySQL 5.7 */
-//#include "partitioning/partition_handler.h"
-#include "ha_partition.h"
+#include "partitioning/partition_handler.h"
/* Forward declarations */
class Altered_partitions;
@@ -62,8 +60,6 @@ private:
/** Pointer back to owning TABLE_SHARE. */
TABLE_SHARE* m_table_share;
- /** Virtual column template */
- innodb_col_templ_t* m_s_templ;
public:
Ha_innopart_share(
TABLE_SHARE* table_share);
@@ -188,7 +184,7 @@ truncate_partition.
InnoDB specific functions related to partitioning is implemented here. */
class ha_innopart:
public ha_innobase,
-// public Partition_helper,
+ public Partition_helper,
public Partition_handler
{
public:
@@ -509,9 +505,7 @@ public:
ft_init_ext_with_hints(
uint inx,
String* key,
- /* JAN: TODO: MySQL 5. /
- Ft_hints* hints)*/
- void* hints)
+ Ft_hints* hints)
{
ut_ad(0);
return(NULL);
@@ -613,7 +607,7 @@ public:
uint
alter_flags(
- uint flags __attribute__((unused))) const
+ uint flags MY_ATTRIBUTE((unused))) const
{
return(HA_PARTITION_FUNCTION_SUPPORTED
| HA_FAST_CHANGE_PARTITION);
@@ -1124,6 +1118,12 @@ private:
THD* thd,
int lock_type);
+ THR_LOCK_DATA**
+ store_lock(
+ THD* thd,
+ THR_LOCK_DATA** to,
+ thr_lock_type lock_type);
+
int
write_row(
uchar* record)
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 5f421d485cf..5904045a022 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2005, 2016, Oracle and/or its affiliates
+Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2016, MariaDB Corporation. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
@@ -82,14 +82,14 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_REBUILD
| Alter_inplace_info::ALTER_COLUMN_ORDER
| Alter_inplace_info::DROP_COLUMN
| Alter_inplace_info::ADD_COLUMN
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_STORED_COLUMNS
| Alter_inplace_info::ALTER_STORED_COLUMN_ORDER
| Alter_inplace_info::DROP_STORED_COLUMN
- | Alter_inplace_info::ADD_STORED_COLUMN
- */
+ | Alter_inplace_info::ADD_STORED_BASE_COLUMN
+ | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE
+#endif
| Alter_inplace_info::RECREATE_TABLE
/*
- | Alter_inplace_info::ALTER_STORED_COLUMN_TYPE
*/
;
@@ -103,6 +103,9 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_INPLACE_IGNORE
| Alter_inplace_info::ALTER_PARTITIONED
| Alter_inplace_info::ALTER_COLUMN_COLUMN_FORMAT
| Alter_inplace_info::ALTER_COLUMN_STORAGE_TYPE
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ | Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR
+#endif
| Alter_inplace_info::ALTER_RENAME;
/** Operations on foreign key definitions (changing the schema only) */
@@ -116,19 +119,19 @@ static const Alter_inplace_info::HA_ALTER_FLAGS INNOBASE_ALTER_NOREBUILD
| INNOBASE_FOREIGN_OPERATIONS
| Alter_inplace_info::DROP_INDEX
| Alter_inplace_info::DROP_UNIQUE_INDEX
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_RENAME_INDEX
| Alter_inplace_info::RENAME_INDEX
- */
+#endif
| Alter_inplace_info::ALTER_COLUMN_NAME
| Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH;
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_VIRTUAL_COLUMNS
| Alter_inplace_info::ALTER_INDEX_COMMENT
| Alter_inplace_info::ADD_VIRTUAL_COLUMN
| Alter_inplace_info::DROP_VIRTUAL_COLUMN
- | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER;
- */
- /* | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE; */
-
+ | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER
+ | Alter_inplace_info::ALTER_VIRTUAL_COLUMN_TYPE
+#endif
+ ;
struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
{
/** Dummy query graph */
@@ -248,7 +251,8 @@ struct ha_innobase_inplace_ctx : public inplace_alter_handler_ctx
}
#endif /* UNIV_DEBUG */
- thr = pars_complete_graph_for_exec(NULL, prebuilt->trx, heap);
+ thr = pars_complete_graph_for_exec(NULL, prebuilt->trx, heap,
+ prebuilt);
}
~ha_innobase_inplace_ctx()
@@ -309,14 +313,7 @@ my_error_innodb(
ut_error;
break;
case DB_TEMP_FILE_WRITE_FAIL:
- /* JAN: TODO: MySQL 5.7
- my_error(ER_GET_ERRMSG, MYF(0),
- DB_TEMP_FILE_WRITE_FAILURE,
- ut_strerr(DB_TEMP_FILE_WRITE_FAILURE),
- "InnoDB");
- */
- my_error(ER_OUT_OF_RESOURCES, MYF(0));
-
+ my_error(ER_TEMP_FILE_WRITE_FAILURE, MYF(0));
break;
case DB_TOO_BIG_INDEX_COL:
my_error(ER_INDEX_COLUMN_TOO_LONG, MYF(0),
@@ -346,12 +343,12 @@ my_error_innodb(
/* TODO: report the row, as we do for DB_DUPLICATE_KEY */
my_error(ER_INVALID_USE_OF_NULL, MYF(0));
break;
- case DB_TABLESPACE_EXISTS:
- my_error(ER_TABLESPACE_EXISTS, MYF(0), table);
- break;
case DB_CANT_CREATE_GEOMETRY_OBJECT:
my_error(ER_CANT_CREATE_GEOMETRY_OBJECT, MYF(0));
break;
+ case DB_TABLESPACE_EXISTS:
+ my_error(ER_TABLESPACE_EXISTS, MYF(0), table);
+ break;
#ifdef UNIV_DEBUG
case DB_SUCCESS:
@@ -457,6 +454,8 @@ innobase_need_rebuild(
return(!!(ha_alter_info->handler_flags & INNOBASE_ALTER_REBUILD));
}
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
/** Check if virtual column in old and new table are in order, excluding
those dropped column. This is needed because when we drop a virtual column,
ALTER_VIRTUAL_COLUMN_ORDER is also turned on, so we can't decide if this
@@ -475,20 +474,49 @@ check_v_col_in_order(
{
ulint j = 0;
+ /* We don't support any adding new virtual column before
+ existed virtual column. */
+ if (ha_alter_info->handler_flags
+ & Alter_inplace_info::ADD_VIRTUAL_COLUMN) {
+ bool has_new = false;
+
+ List_iterator_fast<Create_field> cf_it(
+ ha_alter_info->alter_info->create_list);
+
+ cf_it.rewind();
+
+ while (const Create_field* new_field = cf_it++) {
+ if (!new_field->is_virtual_gcol()) {
+ continue;
+ }
+
+ /* Found a new added virtual column. */
+ if (!new_field->field) {
+ has_new = true;
+ continue;
+ }
+
+ /* If there's any old virtual column
+ after the new added virtual column,
+ order must be changed. */
+ if (has_new) {
+ return(false);
+ }
+ }
+ }
+
/* directly return true if ALTER_VIRTUAL_COLUMN_ORDER is not on */
- /* JAN: TODO: MySQL 5.7
if (!(ha_alter_info->handler_flags
& Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER)) {
return(true);
}
- */
for (ulint i = 0; i < table->s->fields; i++) {
Field* field = table->s->field[i];
bool dropped = false;
Alter_drop* drop;
- if (field->stored_in_db()) {
+ if (field->stored_in_db) {
continue;
}
@@ -513,9 +541,9 @@ check_v_col_in_order(
/* Now check if the next virtual column in altered table
matches this column */
while (j < altered_table->s->fields) {
- Field* new_field = altered_table->s->field[j];
+ Field* new_field = altered_table->s->field[j];
- if (new_field->stored_in_db()) {
+ if (new_field->stored_in_db) {
j++;
continue;
}
@@ -541,6 +569,7 @@ check_v_col_in_order(
return(true);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/** Check if InnoDB supports a particular alter table in-place
@param altered_table TABLE object for new version of table.
@@ -569,9 +598,7 @@ ha_innobase::check_if_supported_inplace_alter(
|| srv_sys_space.created_new_raw()
|| srv_force_recovery) {
ha_alter_info->unsupported_reason = (srv_force_recovery)?
- innobase_get_err_msg(ER_READ_ONLY_MODE):
- // JAN: TODO: MySQL 5.7
- // innobase_get_err_msg(ER_INNODB_FORCED_RECOVERY):
+ innobase_get_err_msg(ER_INNODB_FORCED_RECOVERY):
innobase_get_err_msg(ER_READ_ONLY_MODE);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
@@ -587,6 +614,21 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
+#ifdef MYSQL_ENCRYPTION
+ /* We don't support change encryption attribute with
+ inplace algorithm. */
+ char* old_encryption = this->table->s->encrypt_type.str;
+ char* new_encryption = altered_table->s->encrypt_type.str;
+
+ if (Encryption::is_none(old_encryption)
+ != Encryption::is_none(new_encryption)) {
+ ha_alter_info->unsupported_reason =
+ innobase_get_err_msg(
+ ER_UNSUPPORTED_ALTER_ENCRYPTION_INPLACE);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
update_thd();
trx_search_latch_release_if_reserved(m_prebuilt->trx);
@@ -618,13 +660,14 @@ ha_innobase::check_if_supported_inplace_alter(
| INNOBASE_ALTER_NOREBUILD
| INNOBASE_ALTER_REBUILD)) {
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_STORED_COLUMNS
if (ha_alter_info->handler_flags
& Alter_inplace_info::ALTER_STORED_COLUMN_TYPE) {
ha_alter_info->unsupported_reason = innobase_get_err_msg(
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_COLUMN_TYPE);
}
- */
+#endif
+
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
@@ -637,11 +680,13 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
+#if 0
if (altered_table->file->ht != ht) {
/* Non-native partitioning table engine. No longer supported,
due to implementation of native InnoDB partitioning. */
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
+#endif
if (!(ha_alter_info->handler_flags & ~INNOBASE_INPLACE_IGNORE)) {
DBUG_RETURN(HA_ALTER_INPLACE_NO_LOCK);
@@ -659,18 +704,6 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
- /* InnoDB cannot IGNORE when creating unique indexes. IGNORE
- should silently delete some duplicate rows. Our inplace_alter
- code will not delete anything from existing indexes. */
- if (ha_alter_info->ignore
- && (ha_alter_info->handler_flags
- & (Alter_inplace_info::ADD_PK_INDEX
- | Alter_inplace_info::ADD_UNIQUE_INDEX))) {
- ha_alter_info->unsupported_reason = innobase_get_err_msg(
- ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_IGNORE);
- DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
- }
-
/* DROP PRIMARY KEY is only allowed in combination with ADD
PRIMARY KEY. */
if ((ha_alter_info->handler_flags
@@ -775,30 +808,31 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ // JAN: TODO: MySQL 5.7 Virtual columns
/* If there is add or drop virtual columns, we will support operations
with these 2 options alone with inplace interface for now */
- /* JAN: TODO: MySQL 5.7
+
if (ha_alter_info->handler_flags
& (Alter_inplace_info::ADD_VIRTUAL_COLUMN
| Alter_inplace_info::DROP_VIRTUAL_COLUMN
| Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER)) {
- ulint flags = ha_alter_info->handler_flags;
- */
+ ulonglong flags = ha_alter_info->handler_flags;
+
/* TODO: uncomment the flags below, once we start to
support them */
- /*
+
flags &= ~(Alter_inplace_info::ADD_VIRTUAL_COLUMN
| Alter_inplace_info::DROP_VIRTUAL_COLUMN
| Alter_inplace_info::ALTER_VIRTUAL_COLUMN_ORDER
- */
- /*
+ | Alter_inplace_info::ALTER_VIRTUAL_GCOL_EXPR
+ /*
| Alter_inplace_info::ALTER_STORED_COLUMN_ORDER
- | Alter_inplace_info::ADD_STORED_COLUMN
+ | Alter_inplace_info::ADD_STORED_BASE_COLUMN
| Alter_inplace_info::DROP_STORED_COLUMN
| Alter_inplace_info::ALTER_STORED_COLUMN_ORDER
| Alter_inplace_info::ADD_UNIQUE_INDEX
- */
- /*
+ */
| Alter_inplace_info::ADD_INDEX
| Alter_inplace_info::DROP_INDEX);
@@ -812,22 +846,10 @@ ha_innobase::check_if_supported_inplace_alter(
ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
- */
- /* Do not support inplace alter table drop virtual
- columns and add index together yet */
- /*
- if ((ha_alter_info->handler_flags
- & Alter_inplace_info::ADD_INDEX)
- && (ha_alter_info->handler_flags
- & Alter_inplace_info::DROP_VIRTUAL_COLUMN)) {
- ha_alter_info->unsupported_reason =
- innobase_get_err_msg(
- ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
- DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
- }
+ add_drop_v_cols = true;
}
- */
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/* We should be able to do the operation in-place.
See if we can do it online (LOCK=NONE). */
@@ -842,6 +864,19 @@ ha_innobase::check_if_supported_inplace_alter(
+ ha_alter_info->key_count;
new_key++) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ /* Do not support adding/droping a vritual column, while
+ there is a table rebuild caused by adding a new FTS_DOC_ID */
+ if ((new_key->flags & HA_FULLTEXT) && add_drop_v_cols
+ && !DICT_TF2_FLAG_IS_SET(m_prebuilt->table,
+ DICT_TF2_FTS_HAS_DOC_ID)) {
+ ha_alter_info->unsupported_reason =
+ innobase_get_err_msg(
+ ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
for (KEY_PART_INFO* key_part = new_key->key_part;
key_part < new_key->key_part + new_key->user_defined_key_parts;
key_part++) {
@@ -861,6 +896,7 @@ ha_innobase::check_if_supported_inplace_alter(
key_part->field = altered_table->field[
key_part->fieldnr];
+
/* In some special cases InnoDB emits "false"
duplicate key errors with NULL key values. Let
us play safe and ensure that we can correctly
@@ -905,9 +941,26 @@ ha_innobase::check_if_supported_inplace_alter(
online = false;
}
- if (innobase_is_v_fld(key_part->field)) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ if (key_part->field->is_virtual_gcol()) {
+ /* Do not support adding index on newly added
+ virtual column, while there is also a drop
+ virtual column in the same clause */
+ if (ha_alter_info->handler_flags
+ & Alter_inplace_info::DROP_VIRTUAL_COLUMN) {
+ ha_alter_info->unsupported_reason =
+ innobase_get_err_msg(
+ ER_UNSUPPORTED_ALTER_INPLACE_ON_VIRTUAL_COLUMN);
+
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+
+ ha_alter_info->unsupported_reason =
+ innobase_get_err_msg(
+ ER_UNSUPPORTED_ALTER_ONLINE_ON_VIRTUAL_COLUMN);
online = false;
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
}
}
@@ -916,19 +969,15 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_ASSERT(!m_prebuilt->table->fts || m_prebuilt->table->fts->doc_col
< dict_table_get_n_user_cols(m_prebuilt->table));
- /*
+#ifdef MYSQL_SPATIAL_INDEX
if (ha_alter_info->handler_flags
& Alter_inplace_info::ADD_SPATIAL_INDEX) {
+ ha_alter_info->unsupported_reason = innobase_get_err_msg(
+ ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS);
online = false;
}
+#endif
- if ((ha_alter_info->handler_flags
- & Alter_inplace_info::ADD_VIRTUAL_COLUMN)
- && (ha_alter_info->handler_flags
- & Alter_inplace_info::ADD_INDEX)) {
- online = false;
- }
- */
if (m_prebuilt->table->fts
&& innobase_fulltext_exist(altered_table)) {
/* FULLTEXT indexes are supposed to remain. */
@@ -987,17 +1036,20 @@ ha_innobase::check_if_supported_inplace_alter(
DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
}
- /*
if (innobase_spatial_exist(altered_table)) {
+#ifdef MYSQL_SPATIAL_INDEX
ha_alter_info->unsupported_reason =
innobase_get_err_msg(
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_GIS);
+#endif
+ ha_alter_info->unsupported_reason = innobase_get_err_msg(
+ ER_INNODB_FT_LIMIT);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
} else {
- */
ha_alter_info->unsupported_reason =
innobase_get_err_msg(
ER_ALTER_OPERATION_NOT_SUPPORTED_REASON_FTS);
- //}
+ }
} else if ((ha_alter_info->handler_flags
& Alter_inplace_info::ADD_INDEX)) {
/* Building a full-text index requires a lock.
@@ -1306,27 +1358,101 @@ next_rec:
return(NULL);
}
-/*************************************************************//**
-Create InnoDB foreign key structure from MySQL alter_info
+#ifdef MYSQL_STORED_COLUMNS
+
+/** Check whether given column is a base of stored column.
+@param[in] col_name column name
+@param[in] table table
+@param[in] s_cols list of stored columns
+@return true if the given column is a base of stored column,else false. */
+static
+bool
+innobase_col_check_fk(
+ const char* col_name,
+ const dict_table_t* table,
+ dict_s_col_list* s_cols)
+{
+ dict_s_col_list::const_iterator it;
+
+ for (it = s_cols->begin();
+ it != s_cols->end(); ++it) {
+ dict_s_col_t s_col = *it;
+
+ for (ulint j = 0; j < s_col.num_base; j++) {
+ if (strcmp(col_name, dict_table_get_col_name(
+ table,
+ s_col.base_col[j]->ind)) == 0) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+/** Check whether the foreign key constraint is on base of any stored columns.
+@param[in] foreign Foriegn key constraing information
+@param[in] table table to which the foreign key objects
+to be added
+@param[in] s_cols list of stored column information in the table.
+@return true if yes, otherwise false. */
+static
+bool
+innobase_check_fk_stored(
+ const dict_foreign_t* foreign,
+ const dict_table_t* table,
+ dict_s_col_list* s_cols)
+{
+ ulint type = foreign->type;
+
+ type &= ~(DICT_FOREIGN_ON_DELETE_NO_ACTION
+ | DICT_FOREIGN_ON_UPDATE_NO_ACTION);
+
+ if (type == 0 || s_cols == NULL) {
+ return(false);
+ }
+
+ for (ulint i = 0; i < foreign->n_fields; i++) {
+ if (innobase_col_check_fk(
+ foreign->foreign_col_names[i], table, s_cols)) {
+ return(true);
+ }
+ }
+
+ return(false);
+}
+#endif /* MYSQL_STORED_COLUMNS */
+
+/** Create InnoDB foreign key structure from MySQL alter_info
+@param[in] ha_alter_info alter table info
+@param[in] table_share TABLE_SHARE
+@param[in] table table object
+@param[in] col_names column names, or NULL to use
+table->col_names
+@param[in] drop_index indexes to be dropped
+@param[in] n_drop_index size of drop_index
+@param[out] add_fk foreign constraint added
+@param[out] n_add_fk number of foreign constraints
+added
+@param[in] trx user transaction
+@param[in] s_cols list of stored column information
@retval true if successful
@retval false on error (will call my_error()) */
static MY_ATTRIBUTE((nonnull(1,2,3,7,8), warn_unused_result))
bool
innobase_get_foreign_key_info(
-/*==========================*/
Alter_inplace_info*
- ha_alter_info, /*!< in: alter table info */
+ ha_alter_info,
const TABLE_SHARE*
- table_share, /*!< in: the TABLE_SHARE */
- dict_table_t* table, /*!< in: table */
- const char** col_names, /*!< in: column names, or NULL
- to use table->col_names */
- dict_index_t** drop_index, /*!< in: indexes to be dropped */
- ulint n_drop_index, /*!< in: size of drop_index[] */
- dict_foreign_t**add_fk, /*!< out: foreign constraint added */
- ulint* n_add_fk, /*!< out: number of foreign
- constraints added */
- const trx_t* trx) /*!< in: user transaction */
+ table_share,
+ dict_table_t* table,
+ const char** col_names,
+ dict_index_t** drop_index,
+ ulint n_drop_index,
+ dict_foreign_t**add_fk,
+ ulint* n_add_fk,
+ const trx_t* trx,
+ dict_s_col_list*s_cols)
{
Key* key;
Foreign_key* fk_key;
@@ -1343,8 +1469,6 @@ innobase_get_foreign_key_info(
while ((key=key_iterator++)) {
if (key->type != Key::FOREIGN_KEY) {
- // JAN: TODO: ?
- // if (key->type != KEYTYPE_FOREIGN) {
continue;
}
@@ -1413,7 +1537,7 @@ innobase_get_foreign_key_info(
add_fk[num_fk] = dict_mem_foreign_create();
#ifndef _WIN32
- if(fk_key->ref_db.str) {
+ if (fk_key->ref_db.str) {
tablename_to_filename(fk_key->ref_db.str, db_name,
MAX_DATABASE_NAME_LEN);
db_namep = db_name;
@@ -1545,6 +1669,14 @@ innobase_get_foreign_key_info(
goto err_exit;
}
+#ifdef MYSQL_STORED_BASE_COLUMNS
+ if (innobase_check_fk_stored(
+ add_fk[num_fk], table, s_cols)) {
+ my_error(ER_CANNOT_ADD_FOREIGN_BASE_COL_STORED, MYF(0));
+ goto err_exit;
+ }
+#endif
+
num_fk++;
}
@@ -1665,7 +1797,7 @@ innobase_rec_to_mysql(
rec, index, ...) */
{
uint n_fields = table->s->stored_fields;
- uint sql_idx = 0;
+ uint sql_idx = 0;
ut_ad(n_fields == dict_table_get_n_user_cols(index->table)
- !!(DICT_TF2_FLAG_IS_SET(index->table,
@@ -1678,8 +1810,9 @@ innobase_rec_to_mysql(
const uchar* ifield;
ulint prefix_col;
- while (!((field= table->field[sql_idx])->stored_in_db()))
- sql_idx++;
+ while (!((field= table->field[sql_idx])->stored_in_db())) {
+ sql_idx++;
+ }
field->reset();
@@ -1720,8 +1853,8 @@ innobase_fields_to_mysql(
const dfield_t* fields) /*!< in: InnoDB index fields */
{
uint n_fields = table->s->stored_fields;
- uint sql_idx = 0;
- ulint num_v = 0;
+ uint sql_idx = 0;
+ ulint num_v = 0;
ut_ad(n_fields == dict_table_get_n_user_cols(index->table)
+ dict_table_get_n_v_cols(index->table)
@@ -1734,8 +1867,9 @@ innobase_fields_to_mysql(
ulint col_n;
ulint prefix_col;
- while (!((field= table->field[sql_idx])->stored_in_db()))
- sql_idx++;
+ while (!((field= table->field[sql_idx])->stored_in_db())) {
+ sql_idx++;
+ }
field->reset();
@@ -1778,8 +1912,9 @@ innobase_row_to_mysql(
const dict_table_t* itab, /*!< in: InnoDB table */
const dtuple_t* row) /*!< in: InnoDB row */
{
- uint n_fields = table->s->stored_fields;
- uint sql_idx = 0;
+ uint n_fields = table->s->stored_fields;
+ uint sql_idx = 0;
+ uint num_v = 0;
/* The InnoDB row may contain an extra FTS_DOC_ID column at the end. */
ut_ad(row->n_fields == dict_table_get_n_cols(itab));
@@ -1789,20 +1924,29 @@ innobase_row_to_mysql(
for (uint i = 0; i < n_fields; i++, sql_idx++) {
Field* field;
- const dfield_t* df = dtuple_get_nth_field(row, i);
- while (!((field= table->field[sql_idx])->stored_in_db()))
- sql_idx++;
+ while (!((field= table->field[sql_idx])->stored_in_db())) {
+ sql_idx++;
+ }
field->reset();
+ if (innobase_is_v_fld(field)) {
+ /* Virtual column are not stored in InnoDB table, so
+ skip it */
+ num_v++;
+ continue;
+ }
+
+ const dfield_t* df = dtuple_get_nth_field(row, i - num_v);
+
if (dfield_is_ext(df) || dfield_is_null(df)) {
field->set_null();
} else {
field->set_notnull();
innobase_col_to_mysql(
- dict_table_get_nth_col(itab, i),
+ dict_table_get_nth_col(itab, i - num_v),
static_cast<const uchar*>(dfield_get_data(df)),
dfield_get_len(df), field);
}
@@ -1894,6 +2038,7 @@ innobase_check_index_keys(
}
}
+#ifdef MYSQL_RENAME_INDEX
/* If a key by the same name is being created and
renamed, the name clash is OK. E.g.
ALTER TABLE t ADD INDEX i (col), RENAME INDEX i TO x
@@ -1901,7 +2046,6 @@ innobase_check_index_keys(
In this case we:
1. rename the existing index from "i" to "x"
2. add the new index "i" */
- /* JAN: TODO: MySQL 5.7
for (uint i = 0; i < info->index_rename_count; i++) {
const KEY_PAIR* pair
= &info->index_rename_buffer[i];
@@ -1910,7 +2054,8 @@ innobase_check_index_keys(
goto name_ok;
}
}
- */
+#endif /* MYSQL_RENAME_INDEX */
+
my_error(ER_WRONG_NAME_FOR_INDEX, MYF(0), key.name);
return(ER_WRONG_NAME_FOR_INDEX);
@@ -1987,7 +2132,6 @@ name_ok:
static
void
innobase_create_index_field_def(
-/*============================*/
const TABLE* altered_table,
const KEY_PART_INFO* key_part,
index_field_t* index_field,
@@ -2024,19 +2168,21 @@ innobase_create_index_field_def(
col_type = get_innobase_type_from_mysql_type(
&is_unsigned, field);
- // JAN: TODO: MySQL 5.7 Virtual columns
- //if (!field->stored_in_db && field->gcol_info) {
- // if (!field->stored_in_db() && false) {
- // index_field->is_v_col = true;
- // index_field->col_no = num_v;
- // } else {
- // index_field->is_v_col = false;
- // index_field->col_no = key_part->fieldnr - num_v;
- //}
-
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ if (!field->stored_in_db && field->gcol_info) {
+ if (!field->stored_in_db && false) {
+ index_field->is_v_col = true;
+ index_field->col_no = num_v;
+ } else {
+ index_field->is_v_col = false;
+ index_field->col_no = key_part->fieldnr - num_v;
+ }
+ }
+#else
index_field->is_v_col = false;
index_field->col_no = key_part->fieldnr - num_m_v;
index_field->col_name = altered_table ? field->field_name : fields[key_part->fieldnr]->field_name;
+#endif /* MYSQL_VIRTUAL_COLUMNS */
if (DATA_LARGE_MTYPE(col_type)
|| (key_part->length < field->pack_length()
@@ -2062,23 +2208,17 @@ index on the table
@param[in] key_clustered true if this is the new clustered index
@param[out] index index definition
@param[in] heap heap where memory is allocated */
+static MY_ATTRIBUTE((nonnull))
void
innobase_create_index_def(
-/*======================*/
- const TABLE* altered_table, /*!< in: MySQL table that is
- being altered */
- const KEY* keys, /*!< in: key definitions */
- ulint key_number, /*!< in: MySQL key number */
- bool new_clustered, /*!< in: true if generating
- a new clustered index
- on the table */
- bool key_clustered, /*!< in: true if this is
- the new clustered index */
- index_def_t* index, /*!< out: index definition */
- mem_heap_t* heap, /*!< in: heap where memory
- is allocated */
- const Field** fields) /*!< in: MySQL table fields
- */
+ const TABLE* altered_table,
+ const KEY* keys,
+ ulint key_number,
+ bool new_clustered,
+ bool key_clustered,
+ index_def_t* index,
+ mem_heap_t* heap,
+ const Field** fields)
{
const KEY* key = &keys[key_number];
ulint i;
@@ -2110,10 +2250,10 @@ innobase_create_index_def(
| HA_BINARY_PACK_KEY)));
index->ind_type = DICT_FTS;
- /* Set plugin parser */
+#ifdef MYSQL_FTS_PARSER
/* Note: key->parser is only parser name,
we need to get parser from altered_table instead */
- /* JAN: TODO: MySQL FTS Parser
+
if (key->flags & HA_USES_PARSER) {
for (ulint j = 0; j < altered_table->s->keys; j++) {
if (ut_strcmp(altered_table->key_info[j].name,
@@ -2141,8 +2281,7 @@ innobase_create_index_def(
index->parser = &fts_default_parser;);
ut_ad(index->parser);
}
- */
- index->parser = &fts_default_parser;
+#endif /* MYSQL_FTS_PARSER */
} else if (key->flags & HA_SPATIAL) {
DBUG_ASSERT(!(key->flags & HA_NOSAME));
index->ind_type = DICT_SPATIAL;
@@ -2159,20 +2298,22 @@ innobase_create_index_def(
index->fields[0].col_no = key->key_part[0].fieldnr - num_v;
index->fields[0].prefix_len = 0;
index->fields[0].is_v_col = false;
- /* JAN: TODO: MySQL 5.7 Virtual columns & spatial indexes
- if (!key->key_part[0].field->stored_in_db()
+
+ #ifdef MYSQL_VIRTUAL_COLUMNS
+ if (!key->key_part[0].field->stored_in_db
&& key->key_part[0].field->gcol_info) {
- */
+
/* Currently, the spatial index cannot be created
on virtual columns. It is blocked in server
layer */
- /*
+
ut_ad(0);
index->fields[0].is_v_col = true;
} else {
- */
+
index->fields[0].is_v_col = false;
- //}
+ }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
} else {
index->ind_type = (key->flags & HA_NOSAME) ? DICT_UNIQUE : 0;
}
@@ -2213,7 +2354,7 @@ innobase_fts_check_doc_id_col(
*fts_doc_col_no = ULINT_UNDEFINED;
const uint n_cols = altered_table->s->stored_fields;
- uint sql_idx = 0;
+ uint sql_idx = 0;
ulint i;
*num_v = 0;
@@ -2566,7 +2707,7 @@ created_clustered:
NULL, altered_table,
&fts_doc_id_col, &num_v)) {
fts_doc_id_col =
- altered_table->s->stored_fields;
+ altered_table->s->stored_fields;
add_fts_doc_id = true;
}
@@ -2743,7 +2884,7 @@ online_retry_drop_indexes_with_trx(
@param drop_fk constraints being dropped
@param n_drop_fk number of constraints that are being dropped
@return whether the constraint is being dropped */
-inline MY_ATTRIBUTE((pure, nonnull, warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
bool
innobase_dropping_foreign(
/*======================*/
@@ -2770,7 +2911,7 @@ column that is being dropped or modified to NOT NULL.
@retval true Not allowed (will call my_error())
@retval false Allowed
*/
-static MY_ATTRIBUTE((pure, nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
innobase_check_foreigns_low(
/*========================*/
@@ -2870,7 +3011,7 @@ column that is being dropped or modified to NOT NULL.
@retval true Not allowed (will call my_error())
@retval false Allowed
*/
-static MY_ATTRIBUTE((pure, nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
innobase_check_foreigns(
/*====================*/
@@ -2996,7 +3137,7 @@ innobase_build_col_map(
dtuple_t* add_cols,
mem_heap_t* heap)
{
- uint old_i, old_innobase_i;
+ uint old_i, old_innobase_i;
DBUG_ENTER("innobase_build_col_map");
DBUG_ASSERT(altered_table != table);
DBUG_ASSERT(new_table != old_table);
@@ -3023,7 +3164,7 @@ innobase_build_col_map(
/* Any dropped columns will map to ULINT_UNDEFINED. */
for (old_innobase_i = 0;
- old_innobase_i + DATA_N_SYS_COLS < old_table->n_cols;
+ old_innobase_i + DATA_N_SYS_COLS < old_table->n_cols;
old_innobase_i++) {
col_map[old_innobase_i] = ULINT_UNDEFINED;
}
@@ -3071,7 +3212,7 @@ innobase_build_col_map(
col_map[old_innobase_i] = i;
goto found_col;
}
- old_innobase_i++;
+ old_innobase_i++;
}
ut_ad(!is_v);
@@ -3113,8 +3254,9 @@ found_col:
+ DATA_N_SYS_COLS + 1
== new_table->n_cols);
col_map[i] = altered_table->s->stored_fields;
- col_map[i] = altered_table->s->fields
+ /* col_map[i] = altered_table->s->fields
- new_table->n_v_cols;
+ */
} else {
DBUG_ASSERT(!DICT_TF2_FLAG_IS_SET(
new_table,
@@ -3303,7 +3445,7 @@ PK columns follows rule(2).
@param[in] new_clust_index index to be compared
@retval true if both indexes have same order.
@retval false. */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
innobase_pk_order_preserved(
const ulint* col_map,
@@ -3530,6 +3672,8 @@ innobase_check_gis_columns(
DBUG_RETURN(DB_SUCCESS);
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
+
/** Collect virtual column info for its addition
@param[in] ha_alter_info Data used during in-place alter
@param[in] altered_table MySQL table that is being altered to
@@ -3590,14 +3734,12 @@ prepare_inplace_add_virtual(
field = altered_table->field[i - 1];
- ulint col_type
- = get_innobase_type_from_mysql_type(
- &is_unsigned, field);
+ ulint col_type
+ = get_innobase_type_from_mysql_type(
+ &is_unsigned, field);
+
- /* JAN: TODO: MySQL 5.7
if (!field->gcol_info || field->stored_in_db) {
- */
- if (field->stored_in_db()) {
my_error(ER_WRONG_KEY_COLUMN, MYF(0),
field->field_name);
return(true);
@@ -3740,10 +3882,8 @@ prepare_inplace_drop_virtual(
= get_innobase_type_from_mysql_type(
&is_unsigned, field);
- /* JAN: TODO: MySQL 5.7
+
if (!field->gcol_info || field->stored_in_db) {
- */
- if (field->stored_in_db()) {
my_error(ER_WRONG_KEY_COLUMN, MYF(0),
field->field_name);
return(true);
@@ -4225,6 +4365,90 @@ innobase_drop_virtual_try(
return(false);
}
+/** Adjust the create index column number from "New table" to
+"old InnoDB table" while we are doing dropping virtual column. Since we do
+not create separate new table for the dropping/adding virtual columns.
+To correctly find the indexed column, we will need to find its col_no
+in the "Old Table", not the "New table".
+@param[in] ha_alter_info Data used during in-place alter
+@param[in] old_table MySQL table as it is before the ALTER operation
+@param[in] num_v_dropped number of virtual column dropped
+@param[in,out] index_def index definition */
+static
+void
+innodb_v_adjust_idx_col(
+ const Alter_inplace_info* ha_alter_info,
+ const TABLE* old_table,
+ ulint num_v_dropped,
+ index_def_t* index_def)
+{
+ List_iterator_fast<Create_field> cf_it(
+ ha_alter_info->alter_info->create_list);
+ for (ulint i = 0; i < index_def->n_fields; i++) {
+#ifdef UNIV_DEBUG
+ bool col_found = false;
+#endif /* UNIV_DEBUG */
+ ulint num_v = 0;
+
+ index_field_t* index_field = &index_def->fields[i];
+
+ /* Only adjust virtual column col_no, since non-virtual
+ column position (in non-vcol list) won't change unless
+ table rebuild */
+ if (!index_field->is_v_col) {
+ continue;
+ }
+
+ const Field* field = NULL;
+
+ cf_it.rewind();
+
+ /* Found the field in the new table */
+ while (const Create_field* new_field = cf_it++) {
+ if (!new_field->is_virtual_gcol()) {
+ continue;
+ }
+
+ field = new_field->field;
+
+ if (num_v == index_field->col_no) {
+ break;
+ }
+ num_v++;
+ }
+
+ if (!field) {
+ /* this means the field is a newly added field, this
+ should have been blocked when we drop virtual column
+ at the same time */
+ ut_ad(num_v_dropped > 0);
+ ut_a(0);
+ }
+
+ ut_ad(field->is_virtual_gcol());
+
+ num_v = 0;
+
+ /* Look for its position in old table */
+ for (uint old_i = 0; old_table->field[old_i]; old_i++) {
+ if (old_table->field[old_i] == field) {
+ /* Found it, adjust its col_no to its position
+ in old table */
+ index_def->fields[i].col_no = num_v;
+ ut_d(col_found = true);
+ break;
+ }
+
+ if (old_table->field[old_i]->is_virtual_gcol()) {
+ num_v++;
+ }
+ }
+
+ ut_ad(col_found);
+ }
+}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
/** Update internal structures with concurrent writes blocked,
while preparing ALTER TABLE.
@@ -4262,8 +4486,8 @@ prepare_inplace_alter_table_dict(
dict_index_t* fts_index = NULL;
ulint new_clustered = 0;
dberr_t error;
+ const char* punch_hole_warning = NULL;
ulint num_fts_index;
- uint sql_idx;
dict_add_v_col_t* add_v = NULL;
ha_innobase_inplace_ctx*ctx;
@@ -4288,7 +4512,7 @@ prepare_inplace_alter_table_dict(
trx_start_if_not_started_xa(ctx->prebuilt->trx, true);
- /* JAN: TODO: MySQL 5.7 Virtual columns
+#ifdef MYSQL_VIRTUAL_COLUMNS
if (ha_alter_info->handler_flags
& Alter_inplace_info::DROP_VIRTUAL_COLUMN) {
if (prepare_inplace_drop_virtual(
@@ -4303,10 +4527,10 @@ prepare_inplace_alter_table_dict(
ha_alter_info, altered_table, old_table)) {
DBUG_RETURN(true);
}
- */
+
/* Need information for newly added virtual columns
for create index */
- /*
+
if (ha_alter_info->handler_flags
& Alter_inplace_info::ADD_INDEX) {
add_v = static_cast<dict_add_v_col_t*>(
@@ -4316,15 +4540,13 @@ prepare_inplace_alter_table_dict(
add_v->v_col_name = ctx->add_vcol_name;
}
}
- */
- /*
-
- JAN: TODO: MySQL 5.7 Virtual columns
- There should be no order change for virtual columns coming in
+ /*
+ There should be no order change for virtual columns coming in
here
- ut_ad(check_v_col_in_order(old_table, altered_table, ha_alter_info));
*/
+ ut_ad(check_v_col_in_order(old_table, altered_table, ha_alter_info));
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/* Create a background transaction for the operations on
the data dictionary tables. */
@@ -4339,9 +4561,8 @@ prepare_inplace_alter_table_dict(
ctx->num_to_add_index = ha_alter_info->index_add_count;
ut_ad(ctx->prebuilt->trx->mysql_thd != NULL);
- /* const char* path = thd_innodb_tmpdir(
+ const char* path = thd_innodb_tmpdir(
ctx->prebuilt->trx->mysql_thd);
- */
index_defs = innobase_create_key_defs(
ctx->heap, ha_alter_info, altered_table, ctx->num_to_add_index,
@@ -4443,7 +4664,6 @@ prepare_inplace_alter_table_dict(
ulint n_mv_cols = 0;
dtuple_t* add_cols;
ulint space_id = 0;
- ulint z = 0;
ulint key_id = FIL_DEFAULT_ENCRYPTION_KEY;
fil_encryption_t mode = FIL_SPACE_ENCRYPTION_DEFAULT;
const char* compression=NULL;
@@ -4500,8 +4720,9 @@ prepare_inplace_alter_table_dict(
/* Use the old tablespace unless the tablespace
is changing. */
if (DICT_TF_HAS_SHARED_SPACE(user_table->flags)
- && (0 == strcmp(ha_alter_info->create_info->tablespace,
- user_table->tablespace))) {
+ && (ha_alter_info->create_info->tablespace == NULL
+ || (0 == strcmp(ha_alter_info->create_info->tablespace,
+ user_table->tablespace)))) {
space_id = user_table->space;
} else if (tablespace_is_shared_space(
ha_alter_info->create_info)) {
@@ -4532,9 +4753,9 @@ prepare_inplace_alter_table_dict(
ulint charset_no;
ulint col_len;
- while (!((field= altered_table->field[sql_idx])->
- stored_in_db()))
- sql_idx++;
+ while (!((field= altered_table->field[sql_idx])->stored_in_db())) {
+ sql_idx++;
+ }
ulint field_type = (ulint) field->type();
bool is_virtual = innobase_is_v_fld(field);
@@ -4607,7 +4828,7 @@ prepare_inplace_alter_table_dict(
}
if (is_virtual) {
- /* JAN: TODO: MySQL 5.7 virtual columns
+#ifdef MYSQL_VIRTUAL_COLUMNS
dict_mem_table_add_v_col(
ctx->new_table, ctx->heap,
field->field_name,
@@ -4617,7 +4838,7 @@ prepare_inplace_alter_table_dict(
| DATA_VIRTUAL,
col_len, i,
field->gcol_info->non_virtual_base_columns());
- */
+#endif /* MYSQL_VIRTUAL_COLUMNS */
} else {
dict_mem_table_add_col(
ctx->new_table, ctx->heap,
@@ -4629,6 +4850,9 @@ prepare_inplace_alter_table_dict(
}
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ ulint z = 0;
+
if (n_v_cols) {
for (uint i = 0; i < altered_table->s->fields; i++) {
dict_v_col_t* v_col;
@@ -4644,45 +4868,52 @@ prepare_inplace_alter_table_dict(
ctx->new_table, field, v_col);
}
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
if (add_fts_doc_id) {
fts_add_doc_id_column(ctx->new_table, ctx->heap);
ctx->new_table->fts->doc_col = fts_doc_id_col;
- // JAN: TODO: MySQL 5.7 Virtual columns
- // ut_ad(fts_doc_id_col
- // == altered_table->s->fields - n_v_cols);
- // ut_ad(fts_doc_id_col == altered_table->s->stored_fields);
+ ut_ad(fts_doc_id_col
+ == altered_table->s->stored_fields - n_v_cols);
+ ut_ad(fts_doc_id_col == altered_table->s->stored_fields);
} else if (ctx->new_table->fts) {
ctx->new_table->fts->doc_col = fts_doc_id_col;
}
- /* JAN: TODO: MySQL 5.7 Compression
+#ifdef MYSQL_COMPRESSION
compression = ha_alter_info->create_info->compress.str;
- if (Compression::validate(compression) != DB_SUCCESS) {
+ if (Compression::validate(compression) != DB_SUCCESS) {
- compression = NULL;
- }
- */
+ compression = NULL;
+ }
+#endif /* MYSQL_COMPRESSION */
error = row_create_table_for_mysql(
ctx->new_table, compression, ctx->trx, false, mode, key_id);
+ punch_hole_warning =
+ (error == DB_IO_NO_PUNCH_HOLE_FS)
+ ? "Punch hole is not supported by the file system"
+ : "Page Compression is not supported for this"
+ " tablespace";
+
switch (error) {
dict_table_t* temp_table;
case DB_IO_NO_PUNCH_HOLE_FS:
-
+ case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
push_warning_printf(
ctx->prebuilt->trx->mysql_thd,
Sql_condition::WARN_LEVEL_WARN,
HA_ERR_UNSUPPORTED,
- "XPunch hole not supported by the file system. "
- "Compression disabled for '%s'",
+ "%s. Compression disabled for '%s'",
+ punch_hole_warning,
ctx->new_table->name.m_name);
error = DB_SUCCESS;
+
case DB_SUCCESS:
/* We need to bump up the table ref count and
before we can use it we need to open the
@@ -4755,6 +4986,17 @@ new_clustered_failed:
}
}
+ for (dict_index_t* index
+ = dict_table_get_first_index(user_table);
+ index != NULL;
+ index = dict_table_get_next_index(index)) {
+ if (!index->to_be_dropped
+ && dict_index_is_corrupted(index)) {
+ my_error(ER_CHECK_NO_SUCH_TABLE, MYF(0));
+ goto error_handled;
+ }
+ }
+
if (!ctx->new_table->fts
&& innobase_fulltext_exist(altered_table)) {
ctx->new_table->fts = fts_create(
@@ -4784,6 +5026,15 @@ new_clustered_failed:
for (ulint a = 0; a < ctx->num_to_add_index; a++) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ if (index_defs[a].ind_type & DICT_VIRTUAL
+ && ctx->num_to_drop_vcol > 0 && !new_clustered) {
+ innodb_v_adjust_idx_col(ha_alter_info, old_table,
+ ctx->num_to_drop_vcol,
+ &index_defs[a]);
+ }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
ctx->add_index[a] = row_merge_create_index(
ctx->trx, ctx->new_table,
&index_defs[a], add_v, ctx->col_names);
@@ -4828,8 +5079,8 @@ new_clustered_failed:
rw_lock_x_lock(&ctx->add_index[a]->lock);
bool ok = row_log_allocate(ctx->add_index[a],
- NULL, true, NULL,
- NULL);
+ NULL, true, NULL, NULL,
+ path);
rw_lock_x_unlock(&ctx->add_index[a]->lock);
if (!ok) {
@@ -4863,7 +5114,7 @@ new_clustered_failed:
clust_index, ctx->new_table,
!(ha_alter_info->handler_flags
& Alter_inplace_info::ADD_PK_INDEX),
- ctx->add_cols, ctx->col_map);
+ ctx->add_cols, ctx->col_map, path);
rw_lock_x_unlock(&clust_index->lock);
if (!ok) {
@@ -5166,6 +5417,7 @@ innobase_check_foreign_key_index(
return(false);
}
+#ifdef MYSQL_RENAME_INDEX
/**
Rename a given index in the InnoDB data dictionary.
@@ -5175,7 +5427,7 @@ Rename a given index in the InnoDB data dictionary.
@retval true Failure
@retval false Success */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
rename_index_in_data_dictionary(
/*============================*/
@@ -5243,7 +5495,7 @@ rename
@retval true Failure
@retval false Success */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
rename_indexes_in_data_dictionary(
/*==============================*/
@@ -5253,7 +5505,6 @@ rename_indexes_in_data_dictionary(
{
DBUG_ENTER("rename_indexes_in_data_dictionary");
- /* JAN: TODO: MySQL 5.7
ut_ad(ctx->num_to_rename == ha_alter_info->index_rename_count);
for (ulint i = 0; i < ctx->num_to_rename; i++) {
@@ -5268,12 +5519,10 @@ rename_indexes_in_data_dictionary(
if (rename_index_in_data_dictionary(index,
pair->new_key->name,
trx)) {
- */
/* failed */
DBUG_RETURN(true);
- /* }
+ }
}
- */
DBUG_RETURN(false);
}
@@ -5322,6 +5571,7 @@ rename_index_in_cache(
DBUG_VOID_RETURN;
}
+#
/**
Rename all indexes in data dictionary cache of a given table that are
specified in ha_alter_info.
@@ -5338,7 +5588,6 @@ rename_indexes_in_cache(
{
DBUG_ENTER("rename_indexes_in_cache");
- /* JAN: TODO: MySQL 5.7
ut_ad(ctx->num_to_rename == ha_alter_info->index_rename_count);
for (ulint i = 0; i < ctx->num_to_rename; i++) {
@@ -5351,10 +5600,60 @@ rename_indexes_in_cache(
rename_index_in_cache(index, pair->new_key->name);
}
- */
DBUG_VOID_RETURN;
}
+#endif /* MYSQL_RENAME_INDEX */
+
+#ifdef MYSQL_STORED_COLUMNS
+/** Fill the stored column information in s_cols list.
+@param[in] altered_table mysql table object
+@param[in] table innodb table object
+@param[out] s_cols list of stored column
+@param[out] s_heap heap for storing stored
+column information. */
+static
+void
+alter_fill_stored_column(
+ const TABLE* altered_table,
+ dict_table_t* table,
+ dict_s_col_list** s_cols,
+ mem_heap_t** s_heap)
+{
+ ulint n_cols = altered_table->s->fields;
+
+ for (ulint i = 0; i < n_cols; i++) {
+ Field* field = altered_table->field[i];
+ dict_s_col_t s_col;
+
+ if (!innobase_is_s_fld(field)) {
+ continue;
+ }
+
+ ulint num_base = field->gcol_info->non_virtual_base_columns();
+ dict_col_t* col = dict_table_get_nth_col(table, i);
+
+ s_col.m_col = col;
+ s_col.s_pos = i;
+
+ if (*s_cols == NULL) {
+ *s_cols = UT_NEW_NOKEY(dict_s_col_list());
+ *s_heap = mem_heap_create(1000);
+ }
+
+ if (num_base != 0) {
+ s_col.base_col = static_cast<dict_col_t**>(mem_heap_zalloc(
+ *s_heap, num_base * sizeof(dict_col_t*)));
+ } else {
+ s_col.base_col = NULL;
+ }
+
+ s_col.num_base = num_base;
+ innodb_base_col_setup_for_stored(table, field, &s_col);
+ (*s_cols)->push_back(s_col);
+ }
+}
+#endif /* MYSQL_STORED_COLUMNS */
/** Allows InnoDB to update internal structures with concurrent
writes blocked (provided that check_if_supported_inplace_alter()
@@ -5394,6 +5693,8 @@ ha_innobase::prepare_inplace_alter_table(
bool add_fts_doc_id = false;
bool add_fts_doc_id_idx = false;
bool add_fts_idx = false;
+ dict_s_col_list*s_cols = NULL;
+ mem_heap_t* s_heap = NULL;
DBUG_ENTER("prepare_inplace_alter_table");
DBUG_ASSERT(!ha_alter_info->handler_ctx);
@@ -5734,7 +6035,7 @@ check_if_ok_to_rename:
}
my_error(ER_CANT_DROP_FIELD_OR_KEY, MYF(0),
- drop->type_name(), drop->name);
+ drop->type_name(), drop->name);
goto err_exit;
found_fk:
continue;
@@ -5886,10 +6187,12 @@ check_if_can_drop_indexes:
}
n_rename_index = 0;
- // JAN: TODO: MySQL 5.7
- //n_rename_index = ha_alter_info->index_rename_count;
rename_index = NULL;
+#ifdef MYSQL_RENAME_INDEX
+
+ n_rename_index = ha_alter_info->index_rename_count;
+
/* Create a list of dict_index_t objects that are to be renamed,
also checking for requests to rename nonexistent indexes. If
the table is going to be rebuilt (new_clustered == true in
@@ -5905,13 +6208,12 @@ check_if_can_drop_indexes:
dict_index_t* index = NULL;
const char* old_name = NULL;
- /* JAN: TODO: MySQL 5.7
const char* old_name = ha_alter_info
->index_rename_buffer[i].old_key->name;
index = dict_table_get_index_on_name(indexed_table,
old_name);
- */
+
if (index == NULL) {
my_error(ER_KEY_DOES_NOT_EXITS, MYF(0),
old_name,
@@ -5922,6 +6224,7 @@ check_if_can_drop_indexes:
rename_index[i] = index;
}
}
+#endif /* MYSQL_RENAME_INDEX */
n_add_fk = 0;
@@ -5929,6 +6232,10 @@ check_if_can_drop_indexes:
& Alter_inplace_info::ADD_FOREIGN_KEY) {
ut_ad(!m_prebuilt->trx->check_foreigns);
+#ifdef MYSQL_STORED_COLUMNS
+ alter_fill_stored_column(altered_table, m_prebuilt->table,
+ &s_cols, &s_heap);
+#endif
add_fk = static_cast<dict_foreign_t**>(
mem_heap_zalloc(
heap,
@@ -5939,7 +6246,7 @@ check_if_can_drop_indexes:
ha_alter_info, table_share,
m_prebuilt->table, col_names,
drop_index, n_drop_index,
- add_fk, &n_add_fk, m_prebuilt->trx)) {
+ add_fk, &n_add_fk, m_prebuilt->trx, s_cols)) {
err_exit:
if (n_drop_index) {
row_mysql_lock_data_dictionary(m_prebuilt->trx);
@@ -5959,8 +6266,18 @@ err_exit:
mem_heap_free(heap);
}
+ if (s_cols != NULL) {
+ UT_DELETE(s_cols);
+ mem_heap_free(s_heap);
+ }
+
goto err_exit_no_heap;
}
+
+ if (s_cols != NULL) {
+ UT_DELETE(s_cols);
+ mem_heap_free(s_heap);
+ }
}
if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA)
@@ -5989,7 +6306,7 @@ err_exit:
}
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_VIRTUAL_COLUMNS
if ((ha_alter_info->handler_flags
& Alter_inplace_info::DROP_VIRTUAL_COLUMN)
&& prepare_inplace_drop_virtual(
@@ -6003,7 +6320,7 @@ err_exit:
ha_alter_info, altered_table, table)) {
DBUG_RETURN(true);
}
- */
+#endif /* MYSQL_VIRTUAL_COLUMNS */
DBUG_RETURN(false);
}
@@ -6020,8 +6337,6 @@ err_exit:
altered_table, &fts_doc_col_no, &num_v)) {
fts_doc_col_no = altered_table->s->stored_fields;
-
- fts_doc_col_no = altered_table->s->fields - num_v;
add_fts_doc_id = true;
add_fts_doc_id_idx = true;
@@ -6061,21 +6376,24 @@ err_exit:
/* See if an AUTO_INCREMENT column was added. */
uint i = 0, innodb_idx= 0;
+ ulint num_v = 0;
List_iterator_fast<Create_field> cf_it(
ha_alter_info->alter_info->create_list);
while (const Create_field* new_field = cf_it++) {
const Field* field;
- if (!new_field->stored_in_db()) {
- i++;
- continue;
- }
+ if (!new_field->stored_in_db()) {
+ i++;
+ continue;
+ }
DBUG_ASSERT(i < altered_table->s->fields);
DBUG_ASSERT(innodb_idx < altered_table->s->stored_fields);
for (uint old_i = 0; table->field[old_i]; old_i++) {
- if (!table->field[old_i]->stored_in_db())
- continue;
+ if (!table->field[old_i]->stored_in_db()) {
+ continue;
+ }
+
if (new_field->field == table->field[old_i]) {
goto found_col;
}
@@ -6108,8 +6426,12 @@ err_exit:
autoinc_col_max_value = innobase_get_int_col_max_value(field);
}
found_col:
+ if (innobase_is_v_fld(new_field)) {
+ ++num_v;
+ }
+
i++;
- innodb_idx++;
+ innodb_idx++;
}
DBUG_ASSERT(heap);
@@ -6135,6 +6457,72 @@ found_col:
add_fts_doc_id_idx));
}
+/** Check that the column is part of a virtual index(index contains
+virtual column) in the table
+@param[in] table Table containing column
+@param[in] col column to be checked
+@return true if this column is indexed with other virtual columns */
+static
+bool
+dict_col_in_v_indexes(
+ dict_table_t* table,
+ dict_col_t* col)
+{
+ for (dict_index_t* index = dict_table_get_next_index(
+ dict_table_get_first_index(table)); index != NULL;
+ index = dict_table_get_next_index(index)) {
+ if (!dict_index_has_virtual(index)) {
+ continue;
+ }
+ for (ulint k = 0; k < index->n_fields; k++) {
+ dict_field_t* field
+ = dict_index_get_nth_field(index, k);
+ if (field->col->ind == col->ind) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
+/* Check whether a columnn length change alter operation requires
+to rebuild the template.
+@param[in] altered_table TABLE object for new version of table.
+@param[in] ha_alter_info Structure describing changes to be done
+ by ALTER TABLE and holding data used
+ during in-place alter.
+@param[in] table table being altered
+@return TRUE if needs rebuild. */
+static
+bool
+alter_templ_needs_rebuild(
+ TABLE* altered_table,
+ Alter_inplace_info* ha_alter_info,
+ dict_table_t* table)
+{
+ ulint i = 0;
+ List_iterator_fast<Create_field> cf_it(
+ ha_alter_info->alter_info->create_list);
+
+ for (Field** fp = altered_table->field; *fp; fp++, i++) {
+ cf_it.rewind();
+ while (const Create_field* cf = cf_it++) {
+ for (ulint j=0; j < table->n_cols; j++) {
+ dict_col_t* cols
+ = dict_table_get_nth_col(table, j);
+ if (cf->length > cols->len
+ && dict_col_in_v_indexes(table, cols)) {
+ return(true);
+ }
+ }
+ }
+ }
+
+ return(false);
+}
+
+
/** Alter the table structure in-place with operations
specified using Alter_inplace_info.
The level of concurrency allowed during this operation depends
@@ -6156,10 +6544,10 @@ ha_innobase::inplace_alter_table(
{
dberr_t error;
dict_add_v_col_t* add_v = NULL;
- innodb_col_templ_t* s_templ = NULL;
- innodb_col_templ_t* old_templ = NULL;
-
-
+ dict_vcol_templ_t* s_templ = NULL;
+ dict_vcol_templ_t* old_templ = NULL;
+ struct TABLE* eval_table = altered_table;
+ bool rebuild_templ = false;
DBUG_ENTER("inplace_alter_table");
DBUG_ASSERT(!srv_read_only_mode);
@@ -6168,7 +6556,6 @@ ha_innobase::inplace_alter_table(
DEBUG_SYNC(m_user_thd, "innodb_inplace_alter_table_enter");
-
if (!(ha_alter_info->handler_flags & INNOBASE_ALTER_DATA)) {
ok_exit:
DEBUG_SYNC(m_user_thd, "innodb_after_inplace_alter_table");
@@ -6208,10 +6595,24 @@ ok_exit:
that carries translation information between MySQL TABLE and InnoDB
table, which indicates the virtual columns and their base columns
info. This is used to do the computation callback, so that the
- data in base columns can be extracted send to server */
- if (ctx->need_rebuild() && ctx->new_table->n_v_cols) {
- s_templ = static_cast<innodb_col_templ_t*>(
- mem_heap_alloc(ctx->heap, sizeof *s_templ));
+ data in base columns can be extracted send to server.
+ If the Column length changes and it is a part of virtual
+ index then we need to rebuild the template. */
+ rebuild_templ
+ = ctx->need_rebuild()
+ || ((ha_alter_info->handler_flags
+ & Alter_inplace_info::ALTER_COLUMN_EQUAL_PACK_LENGTH)
+ && alter_templ_needs_rebuild(
+ altered_table, ha_alter_info, ctx->new_table));
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ if ((ctx->new_table->n_v_cols > 0) && rebuild_templ) {
+ /* Save the templ if isn't NULL so as to restore the
+ original state in case of alter operation failures. */
+ if (ctx->new_table->vc_templ != NULL && !ctx->need_rebuild()) {
+ old_templ = ctx->new_table->vc_templ;
+ }
+ s_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
s_templ->vtempl = NULL;
innobase_build_v_templ(
@@ -6219,10 +6620,13 @@ ok_exit:
NULL, false, NULL);
ctx->new_table->vc_templ = s_templ;
- } else if (ctx->num_to_add_vcol) {
- ut_ad(!ctx->online);
- s_templ = static_cast<innodb_col_templ_t*>(
- mem_heap_alloc(ctx->heap, sizeof *s_templ));
+ } else if (ctx->num_to_add_vcol > 0 && ctx->num_to_drop_vcol == 0) {
+ /* if there is ongoing drop virtual column, then we disallow
+ inplace add index on newly added virtual column, so it does
+ not need to come in here to rebuild template with add_v.
+ Please also see the assertion in innodb_v_adjust_idx_col() */
+
+ s_templ = UT_NEW_NOKEY(dict_vcol_templ_t());
add_v = static_cast<dict_add_v_col_t*>(
mem_heap_alloc(ctx->heap, sizeof *add_v));
@@ -6239,6 +6643,14 @@ ok_exit:
ctx->new_table->vc_templ = s_templ;
}
+ /* Drop virtual column without rebuild will keep dict table
+ unchanged, we use old table to evaluate virtual column value
+ in innobase_get_computed_value(). */
+ if (!ctx->need_rebuild() && ctx->num_to_drop_vcol > 0) {
+ eval_table = table;
+ }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
/* Read the clustered index of the table and build
indexes based on this information using temporary
files and merge sort. */
@@ -6252,15 +6664,15 @@ ok_exit:
ctx->add_index, ctx->add_key_numbers, ctx->num_to_add_index,
altered_table, ctx->add_cols, ctx->col_map,
ctx->add_autoinc, ctx->sequence, ctx->skip_pk_sort,
- ctx->m_stage, add_v);
+ ctx->m_stage, add_v, eval_table);
if (s_templ) {
- ut_ad(ctx->need_rebuild() || ctx->num_to_add_vcol);
- free_vc_templ(s_templ);
+ ut_ad(ctx->need_rebuild() || ctx->num_to_add_vcol > 0
+ || rebuild_templ);
+ dict_free_vc_templ(s_templ);
+ UT_DELETE(s_templ);
- if (old_templ) {
- ctx->new_table->vc_templ = old_templ;
- }
+ ctx->new_table->vc_templ = old_templ;
}
#ifndef DBUG_OFF
@@ -6378,6 +6790,56 @@ innobase_online_rebuild_log_free(
rw_lock_x_unlock(&clust_index->lock);
}
+/** For each user column, which is part of an index which is not going to be
+dropped, it checks if the column number of the column is same as col_no
+argument passed.
+@param[in] table table object
+@param[in] col_no column number of the column which is to be checked
+@param[in] is_v if this is a virtual column
+@retval true column exists
+@retval false column does not exist, true if column is system column or
+it is in the index. */
+static
+bool
+check_col_exists_in_indexes(
+ const dict_table_t* table,
+ ulint col_no,
+ bool is_v)
+{
+ /* This function does not check system columns */
+ if (!is_v && dict_table_get_nth_col(table, col_no)->mtype == DATA_SYS) {
+ return(true);
+ }
+
+ for (dict_index_t* index = dict_table_get_first_index(table); index;
+ index = dict_table_get_next_index(index)) {
+
+ if (index->to_be_dropped) {
+ continue;
+ }
+
+ for (ulint i = 0; i < index->n_user_defined_cols; i++) {
+ const dict_col_t* idx_col
+ = dict_index_get_nth_col(index, i);
+
+ if (is_v && dict_col_is_virtual(idx_col)) {
+ const dict_v_col_t* v_col = reinterpret_cast<
+ const dict_v_col_t*>(idx_col);
+ if (v_col->v_pos == col_no) {
+ return(true);
+ }
+ }
+
+ if (!is_v && !dict_col_is_virtual(idx_col)
+ && dict_col_get_no(idx_col) == col_no) {
+ return(true);
+ }
+ }
+ }
+
+ return(false);
+}
+
/** Rollback a secondary index creation, drop the indexes with
temparary index prefix
@param user_table InnoDB table
@@ -6527,6 +6989,21 @@ func_exit:
}
}
+ /* Reset dict_col_t::ord_part for those columns fail to be indexed,
+ we do this by checking every existing column, if any current
+ index would index them */
+ for (ulint i = 0; i < dict_table_get_n_cols(prebuilt->table); i++) {
+ if (!check_col_exists_in_indexes(prebuilt->table, i, false)) {
+ prebuilt->table->cols[i].ord_part = 0;
+ }
+ }
+
+ for (ulint i = 0; i < dict_table_get_n_v_cols(prebuilt->table); i++) {
+ if (!check_col_exists_in_indexes(prebuilt->table, i, true)) {
+ prebuilt->table->v_cols[i].m_col.ord_part = 0;
+ }
+ }
+
trx_commit_for_mysql(prebuilt->trx);
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
DBUG_RETURN(fail);
@@ -6822,8 +7299,8 @@ innobase_rename_columns_try(
for (Field** fp = table->field; *fp; fp++, i++) {
bool is_virtual = innobase_is_v_fld(*fp);
- if (!((*fp)->flags & FIELD_IS_RENAMED) || !((*fp)->stored_in_db())) {
+ if (!((*fp)->flags & FIELD_IS_RENAMED)) {
goto processed_field;
}
@@ -6866,9 +7343,10 @@ processed_field:
@param table_name Table name in MySQL
@param nth_col 0-based index of the column
@param new_len new column length, in bytes
+@param is_v if it's a virtual column
@retval true Failure
@retval false Success */
-static __attribute__((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
bool
innobase_enlarge_column_try(
/*========================*/
@@ -6876,10 +7354,16 @@ innobase_enlarge_column_try(
trx_t* trx,
const char* table_name,
ulint nth_col,
- ulint new_len)
+ ulint new_len,
+ bool is_v)
{
pars_info_t* info;
dberr_t error;
+#ifdef UNIV_DEBUG
+ dict_col_t* col;
+#endif /* UNIV_DEBUG */
+ dict_v_col_t* v_col;
+ ulint pos;
DBUG_ENTER("innobase_enlarge_column_try");
@@ -6887,9 +7371,23 @@ innobase_enlarge_column_try(
ut_ad(trx->dict_operation_lock_mode == RW_X_LATCH);
ut_ad(mutex_own(&dict_sys->mutex));
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
- ut_ad(dict_table_get_nth_col(user_table, nth_col)->len < new_len);
+
+ if (is_v) {
+ v_col = dict_table_get_nth_v_col(user_table, nth_col);
+ pos = dict_create_v_col_pos(v_col->v_pos, v_col->m_col.ind);
+#ifdef UNIV_DEBUG
+ col = &v_col->m_col;
+#endif /* UNIV_DEBUG */
+ } else {
#ifdef UNIV_DEBUG
- switch (dict_table_get_nth_col(user_table, nth_col)->mtype) {
+ col = dict_table_get_nth_col(user_table, nth_col);
+#endif /* UNIV_DEBUG */
+ pos = nth_col;
+ }
+
+#ifdef UNIV_DEBUG
+ ut_ad(col->len < new_len);
+ switch (col->mtype) {
case DATA_MYSQL:
/* NOTE: we could allow this when !(prtype & DATA_BINARY_TYPE)
and ROW_FORMAT is not REDUNDANT and mbminlen<mbmaxlen.
@@ -6909,7 +7407,7 @@ innobase_enlarge_column_try(
info = pars_info_create();
pars_info_add_ull_literal(info, "tableid", user_table->id);
- pars_info_add_int4_literal(info, "nth", nth_col);
+ pars_info_add_int4_literal(info, "nth", pos);
pars_info_add_int4_literal(info, "new", new_len);
trx->op_info = "resizing column in SYS_COLUMNS";
@@ -6945,7 +7443,7 @@ innobase_enlarge_column_try(
@param table_name Table name in MySQL
@retval true Failure
@retval false Success */
-static __attribute__((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
bool
innobase_enlarge_columns_try(
/*=========================*/
@@ -6957,9 +7455,27 @@ innobase_enlarge_columns_try(
{
List_iterator_fast<Create_field> cf_it(
ha_alter_info->alter_info->create_list);
- ulint i = 0;
+ ulint i = 0;
+ bool is_v=false;
for (Field** fp = table->field; *fp; fp++, i++) {
+ ulint idx;
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ ulint num_v = 0;
+ if ((*fp)->is_virtual_gcol()) {
+ is_v = true;
+ idx = num_v;
+ num_v++;
+ } else {
+ idx = i - num_v;
+ is_v = false;
+ }
+#else
+ idx = i;
+ is_v = false;
+#endif
+
cf_it.rewind();
while (Create_field* cf = cf_it++) {
if (cf->field == *fp) {
@@ -6967,7 +7483,7 @@ innobase_enlarge_columns_try(
== IS_EQUAL_PACK_LENGTH
&& innobase_enlarge_column_try(
user_table, trx, table_name,
- i, cf->length)) {
+ idx, cf->length, is_v)) {
return(true);
}
@@ -7468,8 +7984,8 @@ commit_try_rebuild(
/* Normally, n_ref_count must be 1, because purge
cannot be executing on this very table as we are
holding dict_operation_lock X-latch. */
-
- error = DB_LOCK_WAIT_TIMEOUT;
+ my_error(ER_TABLE_REFERENCED,MYF(0));
+ DBUG_RETURN(true);
}
switch (error) {
@@ -7522,6 +8038,9 @@ commit_cache_rebuild(
DBUG_VOID_RETURN;
}
+/** Set of column numbers */
+typedef std::set<ulint, std::less<ulint>, ut_allocator<ulint> > col_set;
+
/** Store the column number of the columns in a list belonging
to indexes which are not being dropped.
@param[in] ctx In-place ALTER TABLE context
@@ -7534,12 +8053,12 @@ static
void
get_col_list_to_be_dropped(
const ha_innobase_inplace_ctx* ctx,
- std::set<ulint>& drop_col_list,
- std::set<ulint>& drop_v_col_list)
+ col_set& drop_col_list,
+ col_set& drop_v_col_list)
{
for (ulint index_count = 0; index_count < ctx->num_to_drop_index;
index_count++) {
- const dict_index_t* index = ctx->drop_index[index_count];
+ const dict_index_t* index = ctx->drop_index[index_count];
for (ulint col = 0; col < index->n_user_defined_cols; col++) {
const dict_col_t* idx_col
@@ -7552,57 +8071,13 @@ get_col_list_to_be_dropped(
drop_v_col_list.insert(v_col->v_pos);
} else {
- ulint col_no = dict_col_get_no(idx_col);
+ ulint col_no = dict_col_get_no(idx_col);
drop_col_list.insert(col_no);
}
}
}
}
-/** For each column, which is part of an index which is not going to be
-dropped, it checks if the column number of the column is same as col_no
-argument passed.
-@param[in] table table object
-@param[in] col_no column number of the column which is to be checked
-@param[in] is_v if this is a virtual column
-@retval true column exists
-@retval false column does not exist. */
-static
-bool
-check_col_exists_in_indexes(
- const dict_table_t* table,
- ulint col_no,
- bool is_v)
-{
- for (dict_index_t* index = dict_table_get_first_index(table); index;
- index = dict_table_get_next_index(index)) {
-
- if (index->to_be_dropped) {
- continue;
- }
-
- for (ulint i = 0; i < index->n_user_defined_cols; i++) {
- const dict_col_t* idx_col
- = dict_index_get_nth_col(index, i);
-
- if (is_v && dict_col_is_virtual(idx_col)) {
- const dict_v_col_t* v_col = reinterpret_cast<
- const dict_v_col_t*>(idx_col);
- if (v_col->v_pos == col_no) {
- return(true);
- }
- }
-
- if (!is_v && !dict_col_is_virtual(idx_col)
- && dict_col_get_no(idx_col) == col_no) {
- return(true);
- }
- }
- }
-
- return(false);
-}
-
/** Commit the changes made during prepare_inplace_alter_table()
and inplace_alter_table() inside the data dictionary tables,
when not rebuilding the table.
@@ -7636,31 +8111,6 @@ commit_try_norebuild(
|| ctx->num_to_drop_vcol
== ha_alter_info->alter_info->drop_list.elements);
-
- std::set<ulint> drop_list;
- std::set<ulint> v_drop_list;
- std::set<ulint>::iterator col_no;
-
- /* Check if the column, part of an index to be dropped is part of any
- other index which is not being dropped. If it so, then set the ord_part
- of the column to 0. */
- get_col_list_to_be_dropped(ctx, drop_list, v_drop_list);
-
- for (col_no = drop_list.begin(); col_no != drop_list.end(); ++col_no) {
- if (!check_col_exists_in_indexes(ctx->new_table,
- *col_no, false)) {
- ctx->new_table->cols[*col_no].ord_part = 0;
- }
- }
-
- for (col_no = v_drop_list.begin();
- col_no != v_drop_list.end(); ++col_no) {
- if (!check_col_exists_in_indexes(ctx->new_table,
- *col_no, true)) {
- ctx->new_table->v_cols[*col_no].m_col.ord_part = 0;
- }
- }
-
for (ulint i = 0; i < ctx->num_to_add_index; i++) {
dict_index_t* index = ctx->add_index[i];
DBUG_ASSERT(dict_index_get_online_status(index)
@@ -7757,13 +8207,15 @@ commit_try_norebuild(
DBUG_RETURN(true);
}
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_RENAME_INDEX
if ((ha_alter_info->handler_flags
& Alter_inplace_info::RENAME_INDEX)
&& rename_indexes_in_data_dictionary(ctx, ha_alter_info, trx)) {
DBUG_RETURN(true);
}
+#endif /* MYSQL_RENAME_INDEX */
+#ifdef MYSQL_VIRTUAL_COLUMNS
if ((ha_alter_info->handler_flags
& Alter_inplace_info::DROP_VIRTUAL_COLUMN)
&& innobase_drop_virtual_try(
@@ -7779,7 +8231,7 @@ commit_try_norebuild(
ctx->old_table, trx)) {
DBUG_RETURN(true);
}
- */
+#endif /* MYSQL_VIRTUAL_COLUMNS */
DBUG_RETURN(false);
}
@@ -7805,6 +8257,30 @@ commit_cache_norebuild(
DBUG_ASSERT(!ctx->need_rebuild());
+ col_set drop_list;
+ col_set v_drop_list;
+ col_set::const_iterator col_it;
+
+ /* Check if the column, part of an index to be dropped is part of any
+ other index which is not being dropped. If it so, then set the ord_part
+ of the column to 0. */
+ get_col_list_to_be_dropped(ctx, drop_list, v_drop_list);
+
+ for (col_it = drop_list.begin(); col_it != drop_list.end(); ++col_it) {
+ if (!check_col_exists_in_indexes(ctx->new_table,
+ *col_it, false)) {
+ ctx->new_table->cols[*col_it].ord_part = 0;
+ }
+ }
+
+ for (col_it = v_drop_list.begin();
+ col_it != v_drop_list.end(); ++col_it) {
+ if (!check_col_exists_in_indexes(ctx->new_table,
+ *col_it, true)) {
+ ctx->new_table->v_cols[*col_it].m_col.ord_part = 0;
+ }
+ }
+
for (ulint i = 0; i < ctx->num_to_add_index; i++) {
dict_index_t* index = ctx->add_index[i];
DBUG_ASSERT(dict_index_get_online_status(index)
@@ -7940,7 +8416,7 @@ alter_stats_norebuild(
}
}
- /* JAN: TODO: MySQL 5.7
+#ifdef MYSQL_RENAME_INDEX
for (i = 0; i < ha_alter_info->index_rename_count; i++) {
KEY_PAIR* pair = &ha_alter_info->index_rename_buffer[i];
dberr_t err;
@@ -7963,7 +8439,7 @@ alter_stats_norebuild(
ut_strerr(err));
}
}
- */
+#endif /* MYSQL_RENAME_INDEX */
for (i = 0; i < ctx->num_to_add_index; i++) {
dict_index_t* index = ctx->add_index[i];
@@ -8063,7 +8539,7 @@ ha_innobase::commit_inplace_alter_table(
Alter_inplace_info* ha_alter_info,
bool commit)
{
- dberr_t error;
+ dberr_t error;
ha_innobase_inplace_ctx*ctx0;
struct mtr_buf_copy_t logs;
@@ -8153,7 +8629,7 @@ ha_innobase::commit_inplace_alter_table(
transactions collected during crash recovery could be
holding InnoDB locks only, not MySQL locks. */
- dberr_t error = row_merge_lock_table(
+ error = row_merge_lock_table(
m_prebuilt->trx, ctx->old_table, LOCK_X);
if (error != DB_SUCCESS) {
@@ -8295,15 +8771,17 @@ ha_innobase::commit_inplace_alter_table(
DBUG_ASSERT(ctx->need_rebuild());
/* Check for any possible problems for any
file operations that will be performed in
- commit_cache_rebuild(). */
- if (!fil_mtr_rename_log(ctx->old_table,
- ctx->new_table,
- ctx->tmp_name, &mtr)) {
- /* Out of memory. */
- mtr.set_log_mode(MTR_LOG_NO_REDO);
- mtr_commit(&mtr);
- trx_rollback_for_mysql(trx);
+ commit_cache_rebuild(), and if none, generate
+ the redo log for these operations. */
+ error = fil_mtr_rename_log(ctx->old_table,
+ ctx->new_table,
+ ctx->tmp_name, &mtr);
+ if (error != DB_SUCCESS) {
+ /* Out of memory or a problem will occur
+ when renaming files. */
fail = true;
+ my_error_innodb(error, ctx->old_table->name.m_name,
+ ctx->old_table->flags);
}
DBUG_INJECT_CRASH("ib_commit_inplace_crash",
crash_inject_count++);
@@ -8319,14 +8797,11 @@ ha_innobase::commit_inplace_alter_table(
DBUG_SUICIDE(););
ut_ad(!trx->fts_trx);
- /* The following call commits the
- mini-transaction, making the data dictionary
- transaction committed at mtr.end_lsn. The
- transaction becomes 'durable' by the time when
- log_buffer_flush_to_disk() returns. In the
- logical sense the commit in the file-based
- data structures happens here. */
- if (!fail) {
+ if (fail) {
+ mtr.set_log_mode(MTR_LOG_NO_REDO);
+ mtr_commit(&mtr);
+ trx_rollback_for_mysql(trx);
+ } else {
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
ut_ad(trx_is_rseg_updated(trx));
@@ -8347,6 +8822,14 @@ ha_innobase::commit_inplace_alter_table(
log_append_on_checkpoint(&logs.m_buf);
}
+ /* The following call commits the
+ mini-transaction, making the data dictionary
+ transaction committed at mtr.end_lsn. The
+ transaction becomes 'durable' by the time when
+ log_buffer_flush_to_disk() returns. In the
+ logical sense the commit in the file-based
+ data structures happens here. */
+
trx_commit_low(trx, &mtr);
}
@@ -8371,7 +8854,6 @@ ha_innobase::commit_inplace_alter_table(
update the in-memory structures, close some handles, release
temporary files, and (unless we rolled back) update persistent
statistics. */
-
for (inplace_alter_handler_ctx** pctx = ctx_array;
*pctx; pctx++) {
ha_innobase_inplace_ctx* ctx
@@ -8459,10 +8941,16 @@ foreign_fail:
innobase_rename_or_enlarge_columns_cache(
ha_alter_info, table,
ctx->new_table);
-
+#ifdef MYSQL_RENAME_INDEX
rename_indexes_in_cache(ctx, ha_alter_info);
+#endif
}
+
}
+
+ dict_mem_table_free_foreign_vcol_set(ctx->new_table);
+ dict_mem_table_fill_foreign_vcol_set(ctx->new_table);
+
DBUG_INJECT_CRASH("ib_commit_inplace_crash",
crash_inject_count++);
}
@@ -8507,6 +8995,14 @@ foreign_fail:
if (ctx0->num_to_drop_vcol || ctx0->num_to_add_vcol) {
+ if (ctx0->old_table->get_ref_count() > 1) {
+
+ row_mysql_unlock_data_dictionary(trx);
+ trx_free_for_mysql(trx);
+ my_error(ER_TABLE_REFERENCED,MYF(0));
+ DBUG_RETURN(true);
+ }
+
trx_commit_for_mysql(m_prebuilt->trx);
if (btr_search_enabled) {
@@ -8523,11 +9019,30 @@ foreign_fail:
dict_table_remove_from_cache(m_prebuilt->table);
m_prebuilt->table = dict_table_open_on_name(
tb_name, TRUE, TRUE, DICT_ERR_IGNORE_NONE);
+
+ /* Drop outdated table stats. */
+ char errstr[1024];
+ if (dict_stats_drop_table(
+ m_prebuilt->table->name.m_name,
+ errstr, sizeof(errstr))
+ != DB_SUCCESS) {
+ push_warning_printf(
+ m_user_thd,
+ Sql_condition::WARN_LEVEL_WARN,
+ ER_ALTER_INFO,
+ "Deleting persistent statistics"
+ " for table '%s' in"
+ " InnoDB failed: %s",
+ table->s->table_name.str,
+ errstr);
+ }
+
row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
MONITOR_ATOMIC_DEC(MONITOR_PENDING_ALTER_TABLE);
DBUG_RETURN(false);
}
+
/* Release the table locks. */
trx_commit_for_mysql(m_prebuilt->trx);
@@ -8626,19 +9141,23 @@ foreign_fail:
row_prebuilt_free(ctx->prebuilt, TRUE);
- if (ctx->new_table->n_v_cols
- && ctx->old_table->vc_templ) {
- refresh_share_vtempl(
- altered_table, ctx->new_table,
- ctx->old_table->vc_templ->share_name);
- }
/* Drop the copy of the old table, which was
renamed to ctx->tmp_name at the atomic DDL
transaction commit. If the system crashes
before this is completed, some orphan tables
with ctx->tmp_name may be recovered. */
trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
- row_merge_drop_table(trx, ctx->old_table);
+ error = row_merge_drop_table(trx, ctx->old_table);
+
+ if (error != DB_SUCCESS) {
+ ib::error() << "Inplace alter table " << ctx->old_table->name.m_name
+ << " dropping copy of the old table failed error "
+ << error
+ << ". tmp_name " << (ctx->tmp_name ? ctx->tmp_name : "N/A")
+ << " new_table " << (ctx->new_table ? ctx->new_table->name.m_name
+ : "N/A");
+ }
+
trx_commit_for_mysql(trx);
/* Rebuild the prebuilt object. */
@@ -8760,6 +9279,332 @@ public:
}
};
+#ifdef MYSQL_INNODB_PARTITIONING
+
+/** Check if supported inplace alter table.
+@param[in] altered_table Altered MySQL table.
+@param[in] ha_alter_info Information about inplace operations to do.
+@return Lock level, not supported or error */
+enum_alter_inplace_result
+ha_innopart::check_if_supported_inplace_alter(
+ TABLE* altered_table,
+ Alter_inplace_info* ha_alter_info)
+{
+ DBUG_ENTER("ha_innopart::check_if_supported_inplace_alter");
+ DBUG_ASSERT(ha_alter_info->handler_ctx == NULL);
+
+ /* Not supporting these for partitioned tables yet! */
+
+ /* FK not yet supported. */
+ if (ha_alter_info->handler_flags
+ & (Alter_inplace_info::ADD_FOREIGN_KEY
+ | Alter_inplace_info::DROP_FOREIGN_KEY)) {
+
+ ha_alter_info->unsupported_reason = innobase_get_err_msg(
+ ER_FOREIGN_KEY_ON_PARTITIONED);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ /* FTS not yet supported either. */
+ if ((ha_alter_info->handler_flags
+ & Alter_inplace_info::ADD_INDEX)) {
+
+ for (uint i = 0; i < ha_alter_info->index_add_count; i++) {
+ const KEY* key =
+ &ha_alter_info->key_info_buffer[
+ ha_alter_info->index_add_buffer[i]];
+ if (key->flags & HA_FULLTEXT) {
+ DBUG_ASSERT(!(key->flags & HA_KEYFLAG_MASK
+ & ~(HA_FULLTEXT
+ | HA_PACK_KEY
+ | HA_GENERATED_KEY
+ | HA_BINARY_PACK_KEY)));
+ ha_alter_info->unsupported_reason =
+ innobase_get_err_msg(
+ ER_FULLTEXT_NOT_SUPPORTED_WITH_PARTITIONING);
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ }
+ }
+ /* We cannot allow INPLACE to change order of KEY partitioning fields! */
+ if ((ha_alter_info->handler_flags
+ & Alter_inplace_info::ALTER_STORED_COLUMN_ORDER)
+ && !m_part_info->same_key_column_order(
+ &ha_alter_info->alter_info->create_list)) {
+
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+
+ /* Cannot allow INPLACE for drop and create PRIMARY KEY if partition is
+ on Primary Key - PARTITION BY KEY() */
+ if ((ha_alter_info->handler_flags
+ & (Alter_inplace_info::ADD_PK_INDEX
+ | Alter_inplace_info::DROP_PK_INDEX))) {
+
+ /* Check partition by key(). */
+ if ((m_part_info->part_type == HASH_PARTITION)
+ && m_part_info->list_of_part_fields
+ && m_part_info->part_field_list.is_empty()) {
+
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+
+ /* Check sub-partition by key(). */
+ if ((m_part_info->subpart_type == HASH_PARTITION)
+ && m_part_info->list_of_subpart_fields
+ && m_part_info->subpart_field_list.is_empty()) {
+
+ DBUG_RETURN(HA_ALTER_INPLACE_NOT_SUPPORTED);
+ }
+ }
+
+ /* Check for PK and UNIQUE should already be done when creating the
+ new table metadata.
+ (fix_partition_info/check_primary_key+check_unique_key) */
+
+ set_partition(0);
+ DBUG_RETURN(ha_innobase::check_if_supported_inplace_alter(altered_table,
+ ha_alter_info));
+}
+
+/** Prepare inplace alter table.
+Allows InnoDB to update internal structures with concurrent
+writes blocked (provided that check_if_supported_inplace_alter()
+did not return HA_ALTER_INPLACE_NO_LOCK).
+This will be invoked before inplace_alter_table().
+@param[in] altered_table TABLE object for new version of table.
+@param[in] ha_alter_info Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+@retval true Failure.
+@retval false Success. */
+bool
+ha_innopart::prepare_inplace_alter_table(
+ TABLE* altered_table,
+ Alter_inplace_info* ha_alter_info)
+{
+ THD* thd;
+ ha_innopart_inplace_ctx* ctx_parts;
+ bool res = true;
+ DBUG_ENTER("ha_innopart::prepare_inplace_alter_table");
+ DBUG_ASSERT(ha_alter_info->handler_ctx == NULL);
+
+ thd = ha_thd();
+
+ /* Clean up all ins/upd nodes. */
+ clear_ins_upd_nodes();
+ /* Based on Sql_alloc class, return NULL for new on failure. */
+ ctx_parts = new ha_innopart_inplace_ctx(thd, m_tot_parts);
+ if (!ctx_parts) {
+ DBUG_RETURN(HA_ALTER_ERROR);
+ }
+
+ uint ctx_array_size = sizeof(inplace_alter_handler_ctx*)
+ * (m_tot_parts + 1);
+ ctx_parts->ctx_array =
+ static_cast<inplace_alter_handler_ctx**>(
+ ut_malloc(ctx_array_size,
+ mem_key_partitioning));
+ if (!ctx_parts->ctx_array) {
+ DBUG_RETURN(HA_ALTER_ERROR);
+ }
+
+ /* Set all to NULL, including the terminating one. */
+ memset(ctx_parts->ctx_array, 0, ctx_array_size);
+
+ ctx_parts->prebuilt_array = static_cast<row_prebuilt_t**>(
+ ut_malloc(sizeof(row_prebuilt_t*)
+ * m_tot_parts,
+ mem_key_partitioning));
+ if (!ctx_parts->prebuilt_array) {
+ DBUG_RETURN(HA_ALTER_ERROR);
+ }
+ /* For the first partition use the current prebuilt. */
+ ctx_parts->prebuilt_array[0] = m_prebuilt;
+ /* Create new prebuilt for the rest of the partitions.
+ It is needed for the current implementation of
+ ha_innobase::commit_inplace_alter_table(). */
+ for (uint i = 1; i < m_tot_parts; i++) {
+ row_prebuilt_t* tmp_prebuilt;
+ tmp_prebuilt = row_create_prebuilt(
+ m_part_share->get_table_part(i),
+ table_share->reclength);
+ /* Use same trx as original prebuilt. */
+ tmp_prebuilt->trx = m_prebuilt->trx;
+ ctx_parts->prebuilt_array[i] = tmp_prebuilt;
+ }
+
+ const char* save_tablespace =
+ ha_alter_info->create_info->tablespace;
+
+ const char* save_data_file_name =
+ ha_alter_info->create_info->data_file_name;
+
+ for (uint i = 0; i < m_tot_parts; i++) {
+ m_prebuilt = ctx_parts->prebuilt_array[i];
+ m_prebuilt_ptr = ctx_parts->prebuilt_array + i;
+ ha_alter_info->handler_ctx = ctx_parts->ctx_array[i];
+ set_partition(i);
+
+ /* Set the tablespace and data_file_name value of the
+ alter_info to the tablespace value and data_file_name
+ value that was existing for the partition originally,
+ so that for ALTER TABLE the tablespace clause in create
+ option is ignored for existing partitions, and later
+ set it back to its old value */
+
+ ha_alter_info->create_info->tablespace =
+ m_prebuilt->table->tablespace;
+ ha_alter_info->create_info->data_file_name =
+ m_prebuilt->table->data_dir_path;
+
+ res = ha_innobase::prepare_inplace_alter_table(altered_table,
+ ha_alter_info);
+ update_partition(i);
+ ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx;
+ if (res) {
+ break;
+ }
+ }
+ m_prebuilt = ctx_parts->prebuilt_array[0];
+ m_prebuilt_ptr = &m_prebuilt;
+ ha_alter_info->handler_ctx = ctx_parts;
+ ha_alter_info->group_commit_ctx = ctx_parts->ctx_array;
+ ha_alter_info->create_info->tablespace = save_tablespace;
+ ha_alter_info->create_info->data_file_name = save_data_file_name;
+ DBUG_RETURN(res);
+}
+
+/** Inplace alter table.
+Alter the table structure in-place with operations
+specified using Alter_inplace_info.
+The level of concurrency allowed during this operation depends
+on the return value from check_if_supported_inplace_alter().
+@param[in] altered_table TABLE object for new version of table.
+@param[in] ha_alter_info Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+@retval true Failure.
+@retval false Success. */
+bool
+ha_innopart::inplace_alter_table(
+ TABLE* altered_table,
+ Alter_inplace_info* ha_alter_info)
+{
+ bool res = true;
+ ha_innopart_inplace_ctx* ctx_parts;
+
+ ctx_parts = static_cast<ha_innopart_inplace_ctx*>(
+ ha_alter_info->handler_ctx);
+ for (uint i = 0; i < m_tot_parts; i++) {
+ m_prebuilt = ctx_parts->prebuilt_array[i];
+ ha_alter_info->handler_ctx = ctx_parts->ctx_array[i];
+ set_partition(i);
+ res = ha_innobase::inplace_alter_table(altered_table,
+ ha_alter_info);
+ ut_ad(ctx_parts->ctx_array[i] == ha_alter_info->handler_ctx);
+ ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx;
+ if (res) {
+ break;
+ }
+ }
+ m_prebuilt = ctx_parts->prebuilt_array[0];
+ ha_alter_info->handler_ctx = ctx_parts;
+ return(res);
+}
+
+/** Commit or rollback inplace alter table.
+Commit or rollback the changes made during
+prepare_inplace_alter_table() and inplace_alter_table() inside
+the storage engine. Note that the allowed level of concurrency
+during this operation will be the same as for
+inplace_alter_table() and thus might be higher than during
+prepare_inplace_alter_table(). (E.g concurrent writes were
+blocked during prepare, but might not be during commit).
+@param[in] altered_table TABLE object for new version of table.
+@param[in] ha_alter_info Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+@param[in] commit true => Commit, false => Rollback.
+@retval true Failure.
+@retval false Success. */
+bool
+ha_innopart::commit_inplace_alter_table(
+ TABLE* altered_table,
+ Alter_inplace_info* ha_alter_info,
+ bool commit)
+{
+ bool res = false;
+ ha_innopart_inplace_ctx* ctx_parts;
+
+ ctx_parts = static_cast<ha_innopart_inplace_ctx*>(
+ ha_alter_info->handler_ctx);
+ ut_ad(ctx_parts);
+ ut_ad(ctx_parts->prebuilt_array);
+ ut_ad(ctx_parts->prebuilt_array[0] == m_prebuilt);
+ if (commit) {
+ /* Commit is done through first partition (group commit). */
+ ut_ad(ha_alter_info->group_commit_ctx == ctx_parts->ctx_array);
+ ha_alter_info->handler_ctx = ctx_parts->ctx_array[0];
+ set_partition(0);
+ res = ha_innobase::commit_inplace_alter_table(altered_table,
+ ha_alter_info,
+ commit);
+ ut_ad(res || !ha_alter_info->group_commit_ctx);
+ goto end;
+ }
+ /* Rollback is done for each partition. */
+ for (uint i = 0; i < m_tot_parts; i++) {
+ m_prebuilt = ctx_parts->prebuilt_array[i];
+ ha_alter_info->handler_ctx = ctx_parts->ctx_array[i];
+ set_partition(i);
+ if (ha_innobase::commit_inplace_alter_table(altered_table,
+ ha_alter_info, commit)) {
+ res = true;
+ }
+ ut_ad(ctx_parts->ctx_array[i] == ha_alter_info->handler_ctx);
+ ctx_parts->ctx_array[i] = ha_alter_info->handler_ctx;
+ }
+end:
+ /* Move the ownership of the new tables back to
+ the m_part_share. */
+ ha_innobase_inplace_ctx* ctx;
+ for (uint i = 0; i < m_tot_parts; i++) {
+ /* TODO: Fix to only use one prebuilt (i.e. make inplace
+ alter partition aware instead of using multiple prebuilt
+ copies... */
+ ctx = static_cast<ha_innobase_inplace_ctx*>(
+ ctx_parts->ctx_array[i]);
+ if (ctx) {
+ m_part_share->set_table_part(i, ctx->prebuilt->table);
+ ctx->prebuilt->table = NULL;
+ ctx_parts->prebuilt_array[i] = ctx->prebuilt;
+ }
+ }
+ /* The above juggling of prebuilt must be reset here. */
+ m_prebuilt = ctx_parts->prebuilt_array[0];
+ m_prebuilt->table = m_part_share->get_table_part(0);
+ ha_alter_info->handler_ctx = ctx_parts;
+ return(res);
+}
+
+/** Notify the storage engine that the table structure (.frm) has
+been updated.
+
+ha_partition allows inplace operations that also upgrades the engine
+if it supports partitioning natively. So if this is the case then
+we will remove the .par file since it is not used with ha_innopart
+(we use the internal data dictionary instead). */
+void
+ha_innopart::notify_table_changed()
+{
+ char tmp_par_path[FN_REFLEN + 1];
+ strxnmov(tmp_par_path, FN_REFLEN, table->s->normalized_path.str,
+ ".par", NullS);
+
+ if (my_access(tmp_par_path, W_OK) == 0)
+ {
+ my_delete(tmp_par_path, MYF(0));
+ }
+}
+#endif /* MYSQL_INNODB_PARTITIONING */
+
/**
@param thd the session
@param start_value the lower bound
diff --git a/storage/innobase/handler/i_s.cc b/storage/innobase/handler/i_s.cc
index 3d7124cdd78..524cbc890f7 100644
--- a/storage/innobase/handler/i_s.cc
+++ b/storage/innobase/handler/i_s.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2007, 2015, Oracle and/or its affiliates.
+Copyright (c) 2007, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyrigth (c) 2014, 2016, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under
@@ -111,6 +111,7 @@ static buf_page_desc_t i_s_page_type[] = {
{"RTREE_INDEX", I_S_PAGE_TYPE_RTREE},
{"IBUF_INDEX", I_S_PAGE_TYPE_IBUF},
{"PAGE COMPRESSED", FIL_PAGE_PAGE_COMPRESSED},
+ {"PAGE COMPRESSED AND ENCRYPTED", FIL_PAGE_PAGE_COMPRESSED_ENCRYPTED},
};
/** This structure defines information we will fetch from pages
@@ -315,7 +316,7 @@ field_store_index_name(
/*******************************************************************//**
Auxiliary function to store ulint value in MYSQL_TYPE_LONGLONG field.
-If the value is ULINT_UNDEFINED then the field it set to NULL.
+If the value is ULINT_UNDEFINED then the field is set to NULL.
@return 0 on success */
int
field_store_ulint(
@@ -327,7 +328,7 @@ field_store_ulint(
if (n != ULINT_UNDEFINED) {
- ret = field->store(static_cast<double>(n));
+ ret = field->store(n, true);
field->set_notnull();
} else {
@@ -628,12 +629,11 @@ fill_innodb_trx_from_cache(
}
/* trx_weight */
- OK(fields[IDX_TRX_WEIGHT]->store((longlong) row->trx_weight,
- true));
+ OK(fields[IDX_TRX_WEIGHT]->store(row->trx_weight, true));
/* trx_mysql_thread_id */
OK(fields[IDX_TRX_MYSQL_THREAD_ID]->store(
- static_cast<double>(row->trx_mysql_thread_id)));
+ row->trx_mysql_thread_id, true));
/* trx_query */
if (row->trx_query) {
@@ -654,31 +654,31 @@ fill_innodb_trx_from_cache(
/* trx_tables_in_use */
OK(fields[IDX_TRX_TABLES_IN_USE]->store(
- (longlong) row->trx_tables_in_use, true));
+ row->trx_tables_in_use, true));
/* trx_tables_locked */
OK(fields[IDX_TRX_TABLES_LOCKED]->store(
- (longlong) row->trx_tables_locked, true));
+ row->trx_tables_locked, true));
/* trx_lock_structs */
OK(fields[IDX_TRX_LOCK_STRUCTS]->store(
- (longlong) row->trx_lock_structs, true));
+ row->trx_lock_structs, true));
/* trx_lock_memory_bytes */
OK(fields[IDX_TRX_LOCK_MEMORY_BYTES]->store(
- (longlong) row->trx_lock_memory_bytes, true));
+ row->trx_lock_memory_bytes, true));
/* trx_rows_locked */
OK(fields[IDX_TRX_ROWS_LOCKED]->store(
- (longlong) row->trx_rows_locked, true));
+ row->trx_rows_locked, true));
/* trx_rows_modified */
OK(fields[IDX_TRX_ROWS_MODIFIED]->store(
- (longlong) row->trx_rows_modified, true));
+ row->trx_rows_modified, true));
/* trx_concurrency_tickets */
OK(fields[IDX_TRX_CONNCURRENCY_TICKETS]->store(
- (longlong) row->trx_concurrency_tickets, true));
+ row->trx_concurrency_tickets, true));
/* trx_isolation_level */
OK(field_store_string(fields[IDX_TRX_ISOLATION_LEVEL],
@@ -686,11 +686,11 @@ fill_innodb_trx_from_cache(
/* trx_unique_checks */
OK(fields[IDX_TRX_UNIQUE_CHECKS]->store(
- static_cast<double>(row->trx_unique_checks)));
+ row->trx_unique_checks, true));
/* trx_foreign_key_checks */
OK(fields[IDX_TRX_FOREIGN_KEY_CHECKS]->store(
- static_cast<double>(row->trx_foreign_key_checks)));
+ row->trx_foreign_key_checks, true));
/* trx_last_foreign_key_error */
OK(field_store_string(fields[IDX_TRX_LAST_FOREIGN_KEY_ERROR],
@@ -698,16 +698,16 @@ fill_innodb_trx_from_cache(
/* trx_adaptive_hash_latched */
OK(fields[IDX_TRX_ADAPTIVE_HASH_LATCHED]->store(
- static_cast<double>(row->trx_has_search_latch)));
+ row->trx_has_search_latch, true));
/* trx_is_read_only*/
OK(fields[IDX_TRX_READ_ONLY]->store(
- (longlong) row->trx_is_read_only, true));
+ row->trx_is_read_only, true));
/* trx_is_autocommit_non_locking */
OK(fields[IDX_TRX_AUTOCOMMIT_NON_LOCKING]->store(
- (longlong) row->trx_is_autocommit_non_locking,
- true));
+ (longlong) row->trx_is_autocommit_non_locking,
+ true));
OK(schema_table_store_record(thd, table));
}
@@ -947,7 +947,7 @@ fill_innodb_locks_from_cache(
strlen(row->lock_table),
thd);
OK(fields[IDX_LOCK_TABLE]->store(
- buf, static_cast<uint>(bufend - buf),
+ buf, static_cast<size_t>(bufend - buf),
system_charset_info));
/* lock_index */
@@ -1427,16 +1427,11 @@ i_s_cmp_fill_low(
clear it. We could introduce mutex protection, but it
could cause a measureable performance hit in
page0zip.cc. */
- table->field[1]->store(
- static_cast<double>(zip_stat->compressed));
- table->field[2]->store(
- static_cast<double>(zip_stat->compressed_ok));
- table->field[3]->store(
- static_cast<double>(zip_stat->compressed_usec / 1000000));
- table->field[4]->store(
- static_cast<double>(zip_stat->decompressed));
- table->field[5]->store(
- static_cast<double>(zip_stat->decompressed_usec / 1000000));
+ table->field[1]->store(zip_stat->compressed, true);
+ table->field[2]->store(zip_stat->compressed_ok, true);
+ table->field[3]->store(zip_stat->compressed_usec / 1000000, true);
+ table->field[4]->store(zip_stat->decompressed, true);
+ table->field[5]->store(zip_stat->decompressed_usec / 1000000, true);
if (reset) {
memset(zip_stat, 0, sizeof *zip_stat);
@@ -1763,25 +1758,36 @@ i_s_cmp_per_index_fill_low(
}
fields[IDX_COMPRESS_OPS]->store(
- static_cast<double>(iter->second.compressed));
+ iter->second.compressed, true);
fields[IDX_COMPRESS_OPS_OK]->store(
- static_cast<double>(iter->second.compressed_ok));
+ iter->second.compressed_ok, true);
fields[IDX_COMPRESS_TIME]->store(
- static_cast<double>(iter->second.compressed_usec / 1000000));
+ iter->second.compressed_usec / 1000000, true);
fields[IDX_UNCOMPRESS_OPS]->store(
- static_cast<double>(iter->second.decompressed));
+ iter->second.decompressed, true);
fields[IDX_UNCOMPRESS_TIME]->store(
- static_cast<double>(iter->second.decompressed_usec / 1000000));
+ iter->second.decompressed_usec / 1000000, true);
+#ifdef MYSQL_SCHEMA_TABLE_STORE_RECORD2
+ int error;
+ if ((error = schema_table_store_record2(thd, table, false))) {
+ mutex_exit(&dict_sys->mutex);
+ if (convert_heap_table_to_ondisk(thd, table, error) != 0) {
+ status = 1;
+ goto err;
+ }
+ mutex_enter(&dict_sys->mutex);
+ }
+#else
if (schema_table_store_record(thd, table)) {
status = 1;
break;
}
-
+#endif
/* Release and reacquire the dict mutex to allow other
threads to proceed. This could eventually result in the
contents of INFORMATION_SCHEMA.innodb_cmp_per_index being
@@ -1793,6 +1799,7 @@ i_s_cmp_per_index_fill_low(
}
mutex_exit(&dict_sys->mutex);
+err:
if (reset) {
page_zip_reset_stat_per_index();
@@ -2046,37 +2053,43 @@ i_s_cmpmem_fill_low(
RETURN_IF_INNODB_NOT_STARTED(tables->schema_table_name);
for (ulint i = 0; i < srv_buf_pool_instances; i++) {
- buf_pool_t* buf_pool;
+ buf_pool_t* buf_pool;
+ ulint zip_free_len_local[BUF_BUDDY_SIZES_MAX + 1];
+ buf_buddy_stat_t buddy_stat_local[BUF_BUDDY_SIZES_MAX + 1];
status = 0;
buf_pool = buf_pool_from_array(i);
+ /* Save buddy stats for buffer pool in local variables. */
buf_pool_mutex_enter(buf_pool);
-
for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
- buf_buddy_stat_t* buddy_stat;
- buddy_stat = &buf_pool->buddy_stat[x];
+ zip_free_len_local[x] = (x < BUF_BUDDY_SIZES) ?
+ UT_LIST_GET_LEN(buf_pool->zip_free[x]) : 0;
- table->field[0]->store(BUF_BUDDY_LOW << x);
- table->field[1]->store(static_cast<double>(i));
- table->field[2]->store(static_cast<double>(
- buddy_stat->used));
- table->field[3]->store(static_cast<double>(
- (x < BUF_BUDDY_SIZES)
- ? UT_LIST_GET_LEN(buf_pool->zip_free[x])
- : 0));
- table->field[4]->store(
- (longlong) buddy_stat->relocated, true);
- table->field[5]->store(
- static_cast<double>(buddy_stat->relocated_usec / 1000000));
+ buddy_stat_local[x] = buf_pool->buddy_stat[x];
if (reset) {
/* This is protected by buf_pool->mutex. */
- buddy_stat->relocated = 0;
- buddy_stat->relocated_usec = 0;
+ buf_pool->buddy_stat[x].relocated = 0;
+ buf_pool->buddy_stat[x].relocated_usec = 0;
}
+ }
+ buf_pool_mutex_exit(buf_pool);
+
+ for (uint x = 0; x <= BUF_BUDDY_SIZES; x++) {
+ buf_buddy_stat_t* buddy_stat;
+
+ buddy_stat = &buddy_stat_local[x];
+
+ table->field[0]->store(BUF_BUDDY_LOW << x);
+ table->field[1]->store(i, true);
+ table->field[2]->store(buddy_stat->used, true);
+ table->field[3]->store(zip_free_len_local[x], true);
+ table->field[4]->store(buddy_stat->relocated, true);
+ table->field[5]->store(
+ buddy_stat->relocated_usec / 1000000, true);
if (schema_table_store_record(thd, table)) {
status = 1;
@@ -2084,8 +2097,6 @@ i_s_cmpmem_fill_low(
}
}
- buf_pool_mutex_exit(buf_pool);
-
if (status) {
break;
}
@@ -2940,15 +2951,26 @@ i_s_fts_deleted_generic_fill(
DBUG_RETURN(0);
}
- deleted = fts_doc_ids_create();
+ /* Prevent DDL to drop fts aux tables. */
+ rw_lock_s_lock(dict_operation_lock);
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
if (!user_table) {
+ rw_lock_s_unlock(dict_operation_lock);
+
+ DBUG_RETURN(0);
+ } else if (!dict_table_has_fts_index(user_table)) {
+ dict_table_close(user_table, FALSE, FALSE);
+
+ rw_lock_s_unlock(dict_operation_lock);
+
DBUG_RETURN(0);
}
+ deleted = fts_doc_ids_create();
+
trx = trx_allocate_for_background();
trx->op_info = "Select for FTS DELETE TABLE";
@@ -2965,7 +2987,7 @@ i_s_fts_deleted_generic_fill(
doc_id = *(doc_id_t*) ib_vector_get_const(deleted->doc_ids, j);
- OK(fields[I_S_FTS_DOC_ID]->store((longlong) doc_id, true));
+ OK(fields[I_S_FTS_DOC_ID]->store(doc_id, true));
OK(schema_table_store_record(thd, table));
}
@@ -2976,6 +2998,8 @@ i_s_fts_deleted_generic_fill(
dict_table_close(user_table, FALSE, FALSE);
+ rw_lock_s_unlock(dict_operation_lock);
+
DBUG_RETURN(0);
}
@@ -3282,28 +3306,28 @@ i_s_fts_index_cache_fill_one_index(
pos = fts_decode_vlc(&ptr);
OK(field_store_string(
- fields[I_S_FTS_WORD],
- word_str));
+ fields[I_S_FTS_WORD],
+ word_str));
OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
- (longlong) node->first_doc_id,
- true));
+ node->first_doc_id,
+ true));
OK(fields[I_S_FTS_LAST_DOC_ID]->store(
- (longlong) node->last_doc_id,
- true));
+ node->last_doc_id,
+ true));
OK(fields[I_S_FTS_DOC_COUNT]->store(
- static_cast<double>(node->doc_count)));
+ node->doc_count, true));
OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
- (longlong) doc_id, true));
+ doc_id, true));
OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
- static_cast<double>(pos)));
+ pos, true));
OK(schema_table_store_record(
- thd, table));
+ thd, table));
}
++ptr;
@@ -3349,6 +3373,12 @@ i_s_fts_index_cache_fill(
DBUG_RETURN(0);
}
+ if (user_table->fts == NULL || user_table->fts->cache == NULL) {
+ dict_table_close(user_table, FALSE, FALSE);
+
+ DBUG_RETURN(0);
+ }
+
cache = user_table->fts->cache;
ut_a(cache);
@@ -3637,8 +3667,8 @@ i_s_fts_index_table_fill_one_fetch(
pos = fts_decode_vlc(&ptr);
OK(field_store_string(
- fields[I_S_FTS_WORD],
- word_str));
+ fields[I_S_FTS_WORD],
+ word_str));
OK(fields[I_S_FTS_FIRST_DOC_ID]->store(
longlong(node->first_doc_id), true));
@@ -3647,16 +3677,16 @@ i_s_fts_index_table_fill_one_fetch(
longlong(node->last_doc_id), true));
OK(fields[I_S_FTS_DOC_COUNT]->store(
- static_cast<double>(node->doc_count)));
+ node->doc_count, true));
OK(fields[I_S_FTS_ILIST_DOC_ID]->store(
longlong(doc_id), true));
OK(fields[I_S_FTS_ILIST_DOC_POS]->store(
- static_cast<double>(pos)));
+ pos, true));
OK(schema_table_store_record(
- thd, table));
+ thd, table));
}
++ptr;
@@ -3780,10 +3810,15 @@ i_s_fts_index_table_fill(
DBUG_RETURN(0);
}
+ /* Prevent DDL to drop fts aux tables. */
+ rw_lock_s_lock(dict_operation_lock);
+
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
if (!user_table) {
+ rw_lock_s_unlock(dict_operation_lock);
+
DBUG_RETURN(0);
}
@@ -3796,6 +3831,8 @@ i_s_fts_index_table_fill(
dict_table_close(user_table, FALSE, FALSE);
+ rw_lock_s_unlock(dict_operation_lock);
+
DBUG_RETURN(0);
}
@@ -3931,14 +3968,21 @@ i_s_fts_config_fill(
fields = table->field;
+ /* Prevent DDL to drop fts aux tables. */
+ rw_lock_s_lock(dict_operation_lock);
+
user_table = dict_table_open_on_name(
fts_internal_tbl_name, FALSE, FALSE, DICT_ERR_IGNORE_NONE);
if (!user_table) {
+ rw_lock_s_unlock(dict_operation_lock);
+
DBUG_RETURN(0);
} else if (!dict_table_has_fts_index(user_table)) {
dict_table_close(user_table, FALSE, FALSE);
+ rw_lock_s_unlock(dict_operation_lock);
+
DBUG_RETURN(0);
}
@@ -3994,6 +4038,8 @@ i_s_fts_config_fill(
dict_table_close(user_table, FALSE, FALSE);
+ rw_lock_s_unlock(dict_operation_lock);
+
DBUG_RETURN(0);
}
@@ -4158,9 +4204,10 @@ i_s_innodb_temp_table_info_fill(
fields = table->field;
- OK(fields[IDX_TEMP_TABLE_ID]->store((double) info->m_table_id));
+ OK(fields[IDX_TEMP_TABLE_ID]->store(info->m_table_id, true));
- OK(field_store_string(fields[IDX_TEMP_TABLE_NAME], info->m_table_name));
+ OK(field_store_string(
+ fields[IDX_TEMP_TABLE_NAME], info->m_table_name));
OK(fields[IDX_TEMP_TABLE_N_COLS]->store(info->m_n_cols));
@@ -4340,9 +4387,8 @@ struct st_maria_plugin i_s_innodb_temp_table_info =
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
- /* Maria extension */
STRUCT_FLD(version_info, INNODB_VERSION_STR),
- STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_BETA),
+ STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_GAMMA)
};
/* Fields of the dynamic table INNODB_BUFFER_POOL_STATS. */
@@ -4662,67 +4708,67 @@ i_s_innodb_stats_fill(
fields = table->field;
OK(fields[IDX_BUF_STATS_POOL_ID]->store(
- static_cast<double>(info->pool_unique_id)));
+ info->pool_unique_id, true));
OK(fields[IDX_BUF_STATS_POOL_SIZE]->store(
- static_cast<double>(info->pool_size)));
+ info->pool_size, true));
OK(fields[IDX_BUF_STATS_LRU_LEN]->store(
- static_cast<double>(info->lru_len)));
+ info->lru_len, true));
OK(fields[IDX_BUF_STATS_OLD_LRU_LEN]->store(
- static_cast<double>(info->old_lru_len)));
+ info->old_lru_len, true));
OK(fields[IDX_BUF_STATS_FREE_BUFFERS]->store(
- static_cast<double>(info->free_list_len)));
+ info->free_list_len, true));
OK(fields[IDX_BUF_STATS_FLUSH_LIST_LEN]->store(
- static_cast<double>(info->flush_list_len)));
+ info->flush_list_len, true));
OK(fields[IDX_BUF_STATS_PENDING_ZIP]->store(
- static_cast<double>(info->n_pend_unzip)));
+ info->n_pend_unzip, true));
OK(fields[IDX_BUF_STATS_PENDING_READ]->store(
- static_cast<double>(info->n_pend_reads)));
+ info->n_pend_reads, true));
OK(fields[IDX_BUF_STATS_FLUSH_LRU]->store(
- static_cast<double>(info->n_pending_flush_lru)));
+ info->n_pending_flush_lru, true));
OK(fields[IDX_BUF_STATS_FLUSH_LIST]->store(
- static_cast<double>(info->n_pending_flush_list)));
+ info->n_pending_flush_list, true));
OK(fields[IDX_BUF_STATS_PAGE_YOUNG]->store(
- static_cast<double>(info->n_pages_made_young)));
+ info->n_pages_made_young, true));
OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG]->store(
- static_cast<double>(info->n_pages_not_made_young)));
+ info->n_pages_not_made_young, true));
OK(fields[IDX_BUF_STATS_PAGE_YOUNG_RATE]->store(
- info->page_made_young_rate));
+ info->page_made_young_rate));
OK(fields[IDX_BUF_STATS_PAGE_NOT_YOUNG_RATE]->store(
- info->page_not_made_young_rate));
+ info->page_not_made_young_rate));
OK(fields[IDX_BUF_STATS_PAGE_READ]->store(
- static_cast<double>(info->n_pages_read)));
+ info->n_pages_read, true));
OK(fields[IDX_BUF_STATS_PAGE_CREATED]->store(
- static_cast<double>(info->n_pages_created)));
+ info->n_pages_created, true));
OK(fields[IDX_BUF_STATS_PAGE_WRITTEN]->store(
- static_cast<double>(info->n_pages_written)));
+ info->n_pages_written, true));
OK(fields[IDX_BUF_STATS_GET]->store(
- static_cast<double>(info->n_page_gets)));
+ info->n_page_gets, true));
OK(fields[IDX_BUF_STATS_PAGE_READ_RATE]->store(
- info->pages_read_rate));
+ info->pages_read_rate));
OK(fields[IDX_BUF_STATS_PAGE_CREATE_RATE]->store(
- info->pages_created_rate));
+ info->pages_created_rate));
OK(fields[IDX_BUF_STATS_PAGE_WRITTEN_RATE]->store(
- info->pages_written_rate));
+ info->pages_written_rate));
if (info->n_page_get_delta) {
if (info->page_read_delta <= info->n_page_get_delta) {
@@ -4735,43 +4781,41 @@ i_s_innodb_stats_fill(
}
OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(
- static_cast<double>(
- 1000 * info->young_making_delta
- / info->n_page_get_delta)));
+ 1000 * info->young_making_delta
+ / info->n_page_get_delta, true));
OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(
- static_cast<double>(
- 1000 * info->not_young_making_delta
- / info->n_page_get_delta)));
+ 1000 * info->not_young_making_delta
+ / info->n_page_get_delta, true));
} else {
- OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0));
- OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0));
- OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0));
+ OK(fields[IDX_BUF_STATS_HIT_RATE]->store(0, true));
+ OK(fields[IDX_BUF_STATS_MADE_YOUNG_PCT]->store(0, true));
+ OK(fields[IDX_BUF_STATS_NOT_MADE_YOUNG_PCT]->store(0, true));
}
OK(fields[IDX_BUF_STATS_READ_AHREAD]->store(
- static_cast<double>(info->n_ra_pages_read)));
+ info->n_ra_pages_read, true));
OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICTED]->store(
- static_cast<double>(info->n_ra_pages_evicted)));
+ info->n_ra_pages_evicted, true));
OK(fields[IDX_BUF_STATS_READ_AHEAD_RATE]->store(
- info->pages_readahead_rate));
+ info->pages_readahead_rate));
OK(fields[IDX_BUF_STATS_READ_AHEAD_EVICT_RATE]->store(
- info->pages_evicted_rate));
+ info->pages_evicted_rate));
OK(fields[IDX_BUF_STATS_LRU_IO_SUM]->store(
- static_cast<double>(info->io_sum)));
+ info->io_sum, true));
OK(fields[IDX_BUF_STATS_LRU_IO_CUR]->store(
- static_cast<double>(info->io_cur)));
+ info->io_cur, true));
OK(fields[IDX_BUF_STATS_UNZIP_SUM]->store(
- static_cast<double>(info->unzip_sum)));
+ info->unzip_sum, true));
OK(fields[IDX_BUF_STATS_UNZIP_CUR]->store(
- static_cast<double>(info->unzip_cur)));
+ info->unzip_cur, true));
DBUG_RETURN(schema_table_store_record(thd, table));
}
@@ -5117,43 +5161,43 @@ i_s_innodb_buffer_page_fill(
state_str = NULL;
OK(fields[IDX_BUFFER_POOL_ID]->store(
- static_cast<double>(page_info->pool_id)));
+ page_info->pool_id, true));
OK(fields[IDX_BUFFER_BLOCK_ID]->store(
- static_cast<double>(page_info->block_id)));
+ page_info->block_id, true));
OK(fields[IDX_BUFFER_PAGE_SPACE]->store(
- static_cast<double>(page_info->space_id)));
+ page_info->space_id, true));
OK(fields[IDX_BUFFER_PAGE_NUM]->store(
- static_cast<double>(page_info->page_num)));
+ page_info->page_num, true));
OK(field_store_string(
- fields[IDX_BUFFER_PAGE_TYPE],
- i_s_page_type[page_info->page_type].type_str));
+ fields[IDX_BUFFER_PAGE_TYPE],
+ i_s_page_type[page_info->page_type].type_str));
OK(fields[IDX_BUFFER_PAGE_FLUSH_TYPE]->store(
- page_info->flush_type));
+ page_info->flush_type));
OK(fields[IDX_BUFFER_PAGE_FIX_COUNT]->store(
- page_info->fix_count));
+ page_info->fix_count));
if (page_info->hashed) {
OK(field_store_string(
- fields[IDX_BUFFER_PAGE_HASHED], "YES"));
+ fields[IDX_BUFFER_PAGE_HASHED], "YES"));
} else {
OK(field_store_string(
- fields[IDX_BUFFER_PAGE_HASHED], "NO"));
+ fields[IDX_BUFFER_PAGE_HASHED], "NO"));
}
OK(fields[IDX_BUFFER_PAGE_NEWEST_MOD]->store(
- (longlong) page_info->newest_mod, true));
+ page_info->newest_mod, true));
OK(fields[IDX_BUFFER_PAGE_OLDEST_MOD]->store(
- (longlong) page_info->oldest_mod, true));
+ page_info->oldest_mod, true));
OK(fields[IDX_BUFFER_PAGE_ACCESS_TIME]->store(
- page_info->access_time));
+ page_info->access_time));
fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_null();
@@ -5178,7 +5222,7 @@ i_s_innodb_buffer_page_fill(
OK(fields[IDX_BUFFER_PAGE_TABLE_NAME]->store(
table_name,
- static_cast<uint>(table_name_end - table_name),
+ static_cast<size_t>(table_name_end - table_name),
system_charset_info));
fields[IDX_BUFFER_PAGE_TABLE_NAME]->set_notnull();
@@ -5191,15 +5235,15 @@ i_s_innodb_buffer_page_fill(
}
OK(fields[IDX_BUFFER_PAGE_NUM_RECS]->store(
- page_info->num_recs));
+ page_info->num_recs, true));
OK(fields[IDX_BUFFER_PAGE_DATA_SIZE]->store(
- page_info->data_size));
+ page_info->data_size, true));
OK(fields[IDX_BUFFER_PAGE_ZIP_SIZE]->store(
- page_info->zip_ssize
- ? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
- : 0));
+ page_info->zip_ssize
+ ? (UNIV_ZIP_SIZE_MIN >> 1) << page_info->zip_ssize
+ : 0, true));
#if BUF_PAGE_STATE_BITS > 3
# error "BUF_PAGE_STATE_BITS > 3, please ensure that all 1<<BUF_PAGE_STATE_BITS values are checked for"
@@ -5258,7 +5302,7 @@ i_s_innodb_buffer_page_fill(
(page_info->is_old) ? "YES" : "NO"));
OK(fields[IDX_BUFFER_PAGE_FREE_CLOCK]->store(
- page_info->freed_page_clock));
+ page_info->freed_page_clock, true));
if (schema_table_store_record(thd, table)) {
DBUG_RETURN(1);
@@ -5835,43 +5879,43 @@ i_s_innodb_buf_page_lru_fill(
page_info = info_array + i;
OK(fields[IDX_BUF_LRU_POOL_ID]->store(
- static_cast<double>(page_info->pool_id)));
+ page_info->pool_id, true));
OK(fields[IDX_BUF_LRU_POS]->store(
- static_cast<double>(page_info->block_id)));
+ page_info->block_id, true));
OK(fields[IDX_BUF_LRU_PAGE_SPACE]->store(
- static_cast<double>(page_info->space_id)));
+ page_info->space_id, true));
OK(fields[IDX_BUF_LRU_PAGE_NUM]->store(
- static_cast<double>(page_info->page_num)));
+ page_info->page_num, true));
OK(field_store_string(
- fields[IDX_BUF_LRU_PAGE_TYPE],
- i_s_page_type[page_info->page_type].type_str));
+ fields[IDX_BUF_LRU_PAGE_TYPE],
+ i_s_page_type[page_info->page_type].type_str));
OK(fields[IDX_BUF_LRU_PAGE_FLUSH_TYPE]->store(
- static_cast<double>(page_info->flush_type)));
+ page_info->flush_type, true));
OK(fields[IDX_BUF_LRU_PAGE_FIX_COUNT]->store(
- static_cast<double>(page_info->fix_count)));
+ page_info->fix_count, true));
if (page_info->hashed) {
OK(field_store_string(
- fields[IDX_BUF_LRU_PAGE_HASHED], "YES"));
+ fields[IDX_BUF_LRU_PAGE_HASHED], "YES"));
} else {
OK(field_store_string(
- fields[IDX_BUF_LRU_PAGE_HASHED], "NO"));
+ fields[IDX_BUF_LRU_PAGE_HASHED], "NO"));
}
OK(fields[IDX_BUF_LRU_PAGE_NEWEST_MOD]->store(
- page_info->newest_mod, true));
+ page_info->newest_mod, true));
OK(fields[IDX_BUF_LRU_PAGE_OLDEST_MOD]->store(
- page_info->oldest_mod, true));
+ page_info->oldest_mod, true));
OK(fields[IDX_BUF_LRU_PAGE_ACCESS_TIME]->store(
- page_info->access_time));
+ page_info->access_time, true));
fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_null();
@@ -5896,7 +5940,7 @@ i_s_innodb_buf_page_lru_fill(
OK(fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->store(
table_name,
- static_cast<uint>(table_name_end - table_name),
+ static_cast<size_t>(table_name_end - table_name),
system_charset_info));
fields[IDX_BUF_LRU_PAGE_TABLE_NAME]->set_notnull();
@@ -5909,14 +5953,14 @@ i_s_innodb_buf_page_lru_fill(
}
OK(fields[IDX_BUF_LRU_PAGE_NUM_RECS]->store(
- page_info->num_recs));
+ page_info->num_recs, true));
OK(fields[IDX_BUF_LRU_PAGE_DATA_SIZE]->store(
- page_info->data_size));
+ page_info->data_size, true));
OK(fields[IDX_BUF_LRU_PAGE_ZIP_SIZE]->store(
- page_info->zip_ssize ?
- 512 << page_info->zip_ssize : 0));
+ page_info->zip_ssize ?
+ 512 << page_info->zip_ssize : 0, true));
state = static_cast<enum buf_page_state>(page_info->page_state);
@@ -5962,7 +6006,7 @@ i_s_innodb_buf_page_lru_fill(
(page_info->is_old) ? "YES" : "NO"));
OK(fields[IDX_BUF_LRU_PAGE_FREE_CLOCK]->store(
- page_info->freed_page_clock));
+ page_info->freed_page_clock, true));
if (schema_table_store_record(thd, table)) {
mem_heap_free(heap);
@@ -6600,35 +6644,34 @@ i_s_dict_fill_sys_tablestats(
"Initialized"));
OK(fields[SYS_TABLESTATS_NROW]->store(table->stat_n_rows,
- TRUE));
+ true));
OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(
- static_cast<double>(table->stat_clustered_index_size)));
+ table->stat_clustered_index_size, true));
OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(
- static_cast<double>(table->stat_sum_of_other_index_sizes)));
+ table->stat_sum_of_other_index_sizes, true));
OK(fields[SYS_TABLESTATS_MODIFIED]->store(
- static_cast<double>(table->stat_modified_counter)));
+ table->stat_modified_counter, true));
} else {
OK(field_store_string(fields[SYS_TABLESTATS_INIT],
"Uninitialized"));
- OK(fields[SYS_TABLESTATS_NROW]->store(0, TRUE));
+ OK(fields[SYS_TABLESTATS_NROW]->store(0, true));
- OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0));
+ OK(fields[SYS_TABLESTATS_CLUST_SIZE]->store(0, true));
- OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0));
+ OK(fields[SYS_TABLESTATS_INDEX_SIZE]->store(0, true));
- OK(fields[SYS_TABLESTATS_MODIFIED]->store(0));
+ OK(fields[SYS_TABLESTATS_MODIFIED]->store(0, true));
}
dict_table_stats_unlock(table, RW_S_LATCH);
- OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, TRUE));
+ OK(fields[SYS_TABLESTATS_AUTONINC]->store(table->autoinc, true));
- OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(
- static_cast<double>(ref_count)));
+ OK(fields[SYS_TABLESTATS_TABLE_REF_COUNT]->store(static_cast<double>(ref_count), true));
OK(schema_table_store_record(thd, table_to_fill));
@@ -6678,10 +6721,24 @@ i_s_sys_tables_fill_table_stats(
heap, rec, &table_rec,
DICT_TABLE_LOAD_FROM_CACHE, &mtr);
- ref_count = table_rec->get_ref_count();
+ if (table_rec != NULL) {
+ ut_ad(err_msg == NULL);
+
+ ref_count = table_rec->get_ref_count();
+
+ /* Protect the dict_table_t object by incrementing
+ the reference count. */
+ table_rec->acquire();
+ }
+
mutex_exit(&dict_sys->mutex);
- if (!err_msg) {
+ DBUG_EXECUTE_IF("test_sys_tablestats", {
+ if (strcmp("test/t1", table_rec->name.m_name) == 0 ) {
+ DEBUG_SYNC_C("dict_table_not_protected");
+ }});
+
+ if (table_rec != NULL) {
i_s_dict_fill_sys_tablestats(thd, table_rec, ref_count,
tables->table);
} else {
@@ -6694,6 +6751,11 @@ i_s_sys_tables_fill_table_stats(
/* Get the next record */
mutex_enter(&dict_sys->mutex);
+
+ if (table_rec != NULL) {
+ table_rec->release();
+ }
+
mtr_start(&mtr);
rec = dict_getnext_system(&pcur, &mtr);
}
@@ -6876,9 +6938,9 @@ i_s_dict_fill_sys_indexes(
OK(field_store_index_name(fields[SYS_INDEX_NAME], index->name));
- OK(fields[SYS_INDEX_ID]->store(longlong(index->id), TRUE));
+ OK(fields[SYS_INDEX_ID]->store(longlong(index->id), true));
- OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), TRUE));
+ OK(fields[SYS_INDEX_TABLE_ID]->store(longlong(table_id), true));
OK(fields[SYS_INDEX_TYPE]->store(index->type));
@@ -7128,9 +7190,9 @@ i_s_dict_fill_sys_columns(
if (dict_col_is_virtual(column)) {
ulint pos = dict_create_v_col_pos(nth_v_col, column->ind);
- OK(fields[SYS_COLUMN_POSITION]->store(pos));
+ OK(fields[SYS_COLUMN_POSITION]->store(pos, true));
} else {
- OK(fields[SYS_COLUMN_POSITION]->store(column->ind));
+ OK(fields[SYS_COLUMN_POSITION]->store(column->ind, true));
}
OK(fields[SYS_COLUMN_MTYPE]->store(column->mtype));
@@ -7487,9 +7549,9 @@ struct st_maria_plugin i_s_innodb_sys_virtual =
/* struct st_mysql_sys_var** */
STRUCT_FLD(system_vars, NULL),
- /* Maria extension */
+ /* Maria extension */
STRUCT_FLD(version_info, INNODB_VERSION_STR),
- STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_BETA),
+ STRUCT_FLD(maturity, MariaDB_PLUGIN_MATURITY_BETA),
};
/** SYS_FIELDS ***************************************************/
/* Fields of the dynamic table INFORMATION_SCHEMA.INNODB_SYS_FIELDS */
@@ -7549,7 +7611,7 @@ i_s_dict_fill_sys_fields(
OK(field_store_string(fields[SYS_FIELD_NAME], field->name));
- OK(fields[SYS_FIELD_POS]->store(static_cast<double>(pos)));
+ OK(fields[SYS_FIELD_POS]->store(static_cast<double>(pos), true));
OK(schema_table_store_record(thd, table_to_fill));
@@ -7997,7 +8059,7 @@ i_s_dict_fill_sys_foreign_cols(
OK(field_store_string(fields[SYS_FOREIGN_COL_REF_NAME], ref_col_name));
- OK(fields[SYS_FOREIGN_COL_POS]->store(static_cast<double>(pos)));
+ OK(fields[SYS_FOREIGN_COL_POS]->store(pos, true));
OK(schema_table_store_record(thd, table_to_fill));
@@ -8246,15 +8308,6 @@ static ST_FIELD_INFO innodb_sys_tablespaces_fields_info[] =
STRUCT_FLD(old_name, ""),
STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
-#define SYS_TABLESPACES_COMPRESSION 11
- {STRUCT_FLD(field_name, "COMPRESSION"),
- STRUCT_FLD(field_length, MAX_COMPRESSION_LEN + 1),
- STRUCT_FLD(field_type, MYSQL_TYPE_STRING),
- STRUCT_FLD(value, 0),
- STRUCT_FLD(field_flags, 0),
- STRUCT_FLD(old_name, ""),
- STRUCT_FLD(open_method, SKIP_OPEN_TABLE)},
-
END_OF_ST_FIELD_INFO
};
@@ -8329,7 +8382,17 @@ i_s_dict_fill_sys_tablespaces(
OK(field_store_string(fields[SYS_TABLESPACES_SPACE_TYPE],
space_type));
- char* filename = fil_make_filepath(NULL, name, IBD, false);
+ char* filepath = NULL;
+ if (FSP_FLAGS_HAS_DATA_DIR(flags)
+ || FSP_FLAGS_GET_SHARED(flags)) {
+ mutex_enter(&dict_sys->mutex);
+ filepath = dict_get_first_path(space);
+ mutex_exit(&dict_sys->mutex);
+ }
+
+ if (filepath == NULL) {
+ filepath = fil_make_filepath(NULL, name, IBD, false);
+ }
os_file_stat_t stat;
os_file_size_t file;
@@ -8337,17 +8400,17 @@ i_s_dict_fill_sys_tablespaces(
memset(&file, 0xff, sizeof(file));
memset(&stat, 0x0, sizeof(stat));
- if (filename != NULL) {
+ if (filepath != NULL) {
- file = os_file_get_size(filename);
+ file = os_file_get_size(filepath);
/* Get the file system (or Volume) block size. */
- dberr_t err = os_file_get_status(filename, &stat, false, false);
+ dberr_t err = os_file_get_status(filepath, &stat, false, false);
switch(err) {
case DB_FAIL:
ib::warn()
- << "File '" << filename << "', failed to get "
+ << "File '" << filepath << "', failed to get "
<< "stats";
break;
@@ -8357,12 +8420,18 @@ i_s_dict_fill_sys_tablespaces(
default:
ib::error()
- << "File '" << filename << "' "
+ << "File '" << filepath << "' "
<< ut_strerr(err);
break;
}
- ut_free(filename);
+ ut_free(filepath);
+ }
+
+ if (file.m_total_size == static_cast<os_offset_t>(~0)) {
+ stat.block_size = 0;
+ file.m_total_size = 0;
+ file.m_alloc_size = 0;
}
OK(fields[SYS_TABLESPACES_FS_BLOCK_SIZE]->store(stat.block_size, true));
@@ -8371,12 +8440,6 @@ i_s_dict_fill_sys_tablespaces(
OK(fields[SYS_TABLESPACES_ALLOC_SIZE]->store(file.m_alloc_size, true));
- Compression::Type type = fil_get_compression(space);
-
- OK(field_store_string(
- fields[SYS_TABLESPACES_COMPRESSION],
- Compression::to_string(type)));
-
OK(schema_table_store_record(thd, table_to_fill));
DBUG_RETURN(0);
@@ -9374,7 +9437,7 @@ i_s_innodb_mutexes_fill_table(
// mutex_enter(&mutex_list_mutex);
- /* JAN: TODO: FIXME:
+#ifdef JAN_TODO_FIXME
for (mutex = UT_LIST_GET_FIRST(os_mutex_list); mutex != NULL;
mutex = UT_LIST_GET_NEXT(list, mutex)) {
if (mutex->count_os_wait == 0) {
@@ -9408,7 +9471,7 @@ i_s_innodb_mutexes_fill_table(
}
mutex_exit(&mutex_list_mutex);
- */
+#endif /* JAN_TODO_FIXME */
mutex_enter(&rw_lock_list_mutex);
diff --git a/storage/innobase/ibuf/ibuf0ibuf.cc b/storage/innobase/ibuf/ibuf0ibuf.cc
index bfdaefc3271..71aa7be3ef7 100644
--- a/storage/innobase/ibuf/ibuf0ibuf.cc
+++ b/storage/innobase/ibuf/ibuf0ibuf.cc
@@ -566,7 +566,7 @@ ibuf_init_at_db_start(void)
ibuf->index = dict_mem_index_create(
"innodb_change_buffer", "CLUST_IND",
- IBUF_SPACE_ID, DICT_CLUSTERED | DICT_IBUF, 1);
+ IBUF_SPACE_ID, DICT_CLUSTERED | DICT_UNIVERSAL | DICT_IBUF, 1);
ibuf->index->id = DICT_IBUF_ID_MIN + IBUF_SPACE_ID;
ibuf->index->table = dict_mem_table_create(
"innodb_change_buffer", IBUF_SPACE_ID, 1, 0, 0, 0);
@@ -828,6 +828,7 @@ ibuf_bitmap_get_map_page_func(
return NULL;
}
+
buf_block_dbg_add_level(block, SYNC_IBUF_BITMAP);
return(buf_block_get_frame(block));
@@ -2245,11 +2246,11 @@ ibuf_free_excess_pages(void)
}
#ifdef UNIV_DEBUG
-# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \
- ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,vers,pages,n_stored)
+# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \
+ ibuf_get_merge_page_nos_func(contract,rec,mtr,ids,pages,n_stored)
#else /* UNIV_DEBUG */
-# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,vers,pages,n_stored) \
- ibuf_get_merge_page_nos_func(contract,rec,ids,vers, pages,n_stored)
+# define ibuf_get_merge_page_nos(contract,rec,mtr,ids,pages,n_stored) \
+ ibuf_get_merge_page_nos_func(contract,rec,ids,pages,n_stored)
#endif /* UNIV_DEBUG */
/*********************************************************************//**
@@ -2272,9 +2273,6 @@ ibuf_get_merge_page_nos_func(
ulint* page_nos,/*!< in/out: buffer for at least
IBUF_MAX_N_PAGES_MERGED many page numbers;
the page numbers are in an ascending order */
- ib_uint64_t* space_versions,/*!< in/out: tablespace version
- timestamps; used to prevent reading in old
- pages after DISCARD + IMPORT tablespace */
ulint* n_stored)/*!< out: number of page numbers stored to
page_nos in this function */
{
@@ -2403,8 +2401,6 @@ ibuf_get_merge_page_nos_func(
/ IBUF_MERGE_THRESHOLD)) {
space_ids[*n_stored] = prev_space_id;
- space_versions[*n_stored]
- = fil_space_get_version(prev_space_id);
page_nos[*n_stored] = prev_page_no;
(*n_stored)++;
@@ -2482,13 +2478,11 @@ ibuf_get_merge_pages(
ulint limit, /*!< in: max page numbers to read */
ulint* pages, /*!< out: pages read */
ulint* spaces, /*!< out: spaces read */
- ib_uint64_t* versions,/*!< out: space versions read */
ulint* n_pages,/*!< out: number of pages read */
mtr_t* mtr) /*!< in: mini transaction */
{
const rec_t* rec;
ulint volume = 0;
- ib_uint64_t version = fil_space_get_version(space);
ut_a(space != ULINT_UNDEFINED);
@@ -2503,7 +2497,6 @@ ibuf_get_merge_pages(
if (*n_pages == 0 || pages[*n_pages - 1] != page_no) {
spaces[*n_pages] = space;
pages[*n_pages] = page_no;
- versions[*n_pages] = version;
++*n_pages;
}
@@ -2534,7 +2527,6 @@ ibuf_merge_pages(
ulint sum_sizes;
ulint page_nos[IBUF_MAX_N_PAGES_MERGED];
ulint space_ids[IBUF_MAX_N_PAGES_MERGED];
- ib_uint64_t space_versions[IBUF_MAX_N_PAGES_MERGED];
*n_pages = 0;
@@ -2570,7 +2562,7 @@ ibuf_merge_pages(
sum_sizes = ibuf_get_merge_page_nos(TRUE,
btr_pcur_get_rec(&pcur), &mtr,
space_ids,
- page_nos, space_versions, n_pages);
+ page_nos, n_pages);
#if 0 /* defined UNIV_IBUF_DEBUG */
fprintf(stderr, "Ibuf contract sync %lu pages %lu volume %lu\n",
sync, *n_pages, sum_sizes);
@@ -2579,7 +2571,7 @@ ibuf_merge_pages(
btr_pcur_close(&pcur);
buf_read_ibuf_merge_pages(
- sync, space_ids, space_versions, page_nos, *n_pages);
+ sync, space_ids, page_nos, *n_pages);
return(sum_sizes + 1);
}
@@ -2588,7 +2580,6 @@ ibuf_merge_pages(
Contracts insert buffer trees by reading pages referring to space_id
to the buffer pool.
@returns number of pages merged.*/
-UNIV_INTERN
ulint
ibuf_merge_space(
/*=============*/
@@ -2619,7 +2610,6 @@ ibuf_merge_space(
ulint sum_sizes = 0;
ulint pages[IBUF_MAX_N_PAGES_MERGED];
ulint spaces[IBUF_MAX_N_PAGES_MERGED];
- ib_uint64_t versions[IBUF_MAX_N_PAGES_MERGED];
if (page_is_empty(btr_pcur_get_page(&pcur))) {
/* If a B-tree page is empty, it must be the root page
@@ -2634,11 +2624,10 @@ ibuf_merge_space(
} else {
sum_sizes = ibuf_get_merge_pages(
- &pcur, space, IBUF_MAX_N_PAGES_MERGED,
- &pages[0], &spaces[0], &versions[0], &n_pages,
- &mtr);
+ &pcur, space, IBUF_MAX_N_PAGES_MERGED,
+ &pages[0], &spaces[0], &n_pages,
+ &mtr);
ib::info() << "Size of pages merged " << sum_sizes;
-
}
ibuf_mtr_commit(&mtr);
@@ -2646,18 +2635,16 @@ ibuf_merge_space(
btr_pcur_close(&pcur);
if (n_pages > 0) {
-
-#ifdef UNIV_DEBUG
ut_ad(n_pages <= UT_ARR_SIZE(pages));
+#ifdef UNIV_DEBUG
for (ulint i = 0; i < n_pages; ++i) {
ut_ad(spaces[i] == space);
- ut_ad(i == 0 || versions[i] == versions[i - 1]);
}
#endif /* UNIV_DEBUG */
buf_read_ibuf_merge_pages(
- true, spaces, versions, pages, n_pages);
+ true, spaces, pages, n_pages);
}
return(n_pages);
@@ -2667,17 +2654,14 @@ ibuf_merge_space(
@param[out] n_pages number of pages merged
@param[in] sync whether the caller waits for
the issued reads to complete
-@param[in] space_id tablespace for which to merge, or
-ULINT_UNDEFINED for all tablespaces
@return a lower limit for the combined size in bytes of entries which
will be merged from ibuf trees to the pages read, 0 if ibuf is
empty */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
ulint
ibuf_merge(
ulint* n_pages,
- bool sync,
- ulint space_id)
+ bool sync)
{
*n_pages = 0;
@@ -2692,10 +2676,8 @@ ibuf_merge(
} else if (ibuf_debug) {
return(0);
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
- } else if (space_id == ULINT_UNDEFINED) {
- return(ibuf_merge_pages(n_pages, sync));
} else {
- return(ibuf_merge_space(space_id));
+ return(ibuf_merge_pages(n_pages, sync));
}
}
@@ -2718,15 +2700,12 @@ ibuf_contract(
@param[in] full If true, do a full contraction based
on PCT_IO(100). If false, the size of contract batch is determined
based on the current size of the change buffer.
-@param[in] space_id tablespace for which to contract, or
-ULINT_UNDEFINED to contract for all tablespaces
@return a lower limit for the combined size in bytes of entries which
will be merged from ibuf trees to the pages read, 0 if ibuf is
empty */
ulint
ibuf_merge_in_background(
- bool full,
- ulint space_id)
+ bool full)
{
ulint sum_bytes = 0;
ulint sum_pages = 0;
@@ -2734,7 +2713,7 @@ ibuf_merge_in_background(
ulint n_pages;
#if defined UNIV_DEBUG || defined UNIV_IBUF_DEBUG
- if (srv_ibuf_disable_background_merge && space_id == ULINT_UNDEFINED) {
+ if (srv_ibuf_disable_background_merge) {
return(0);
}
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
@@ -2771,7 +2750,7 @@ ibuf_merge_in_background(
while (sum_pages < n_pages) {
ulint n_bytes;
- n_bytes = ibuf_merge(&n_pag2, false, space_id);
+ n_bytes = ibuf_merge(&n_pag2, false);
if (n_bytes == 0) {
return(sum_bytes);
@@ -3383,7 +3362,7 @@ or clustered
@param[in] page_size page size
@param[in,out] thr query thread
@return DB_SUCCESS, DB_STRONG_FAIL or other error */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
ibuf_insert_low(
ulint mode,
@@ -3414,7 +3393,6 @@ ibuf_insert_low(
ibool do_merge;
ulint space_ids[IBUF_MAX_N_PAGES_MERGED];
ulint page_nos[IBUF_MAX_N_PAGES_MERGED];
- ib_uint64_t space_versions[IBUF_MAX_N_PAGES_MERGED];
ulint n_stored;
mtr_t mtr;
mtr_t bitmap_mtr;
@@ -3576,7 +3554,7 @@ fail_exit:
ibuf_get_merge_page_nos(FALSE,
btr_pcur_get_rec(&pcur), &mtr,
space_ids,
- page_nos, space_versions, &n_stored);
+ page_nos, &n_stored);
goto fail_exit;
}
@@ -3711,7 +3689,7 @@ func_exit:
#ifdef UNIV_IBUF_DEBUG
ut_a(n_stored <= IBUF_MAX_N_PAGES_MERGED);
#endif
- buf_read_ibuf_merge_pages(false, space_ids, space_versions,
+ buf_read_ibuf_merge_pages(false, space_ids,
page_nos, n_stored);
}
@@ -3973,7 +3951,7 @@ ibuf_insert_to_index_page(
ut_ad(!dict_index_is_online_ddl(index));// this is an ibuf_dummy index
ut_ad(ibuf_inside(mtr));
ut_ad(dtuple_check_typed(entry));
- ut_ad(!buf_block_align(page)->index);
+ ut_ad(!block->index);
ut_ad(mtr->is_named_space(block->page.id.space()));
if (UNIV_UNLIKELY(dict_table_is_comp(index->table)
@@ -4813,7 +4791,6 @@ reset_bit:
os_atomic_increment_ulint(&ibuf->n_merges, 1);
ibuf_add_ops(ibuf->n_merged_ops, mops);
ibuf_add_ops(ibuf->n_discarded_ops, dops);
-
if (space != NULL) {
fil_space_release(space);
}
diff --git a/storage/innobase/include/api0api.h b/storage/innobase/include/api0api.h
index 127f8e1949e..ec02febee74 100644
--- a/storage/innobase/include/api0api.h
+++ b/storage/innobase/include/api0api.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2011, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2012, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -1030,4 +1030,11 @@ ib_ut_strerr(
/*=========*/
ib_err_t num); /*!< in: error number */
+/** Check the table whether it contains virtual columns.
+@param[in] crsr InnoDB Cursor
+@return true if table contains virtual column else false. */
+ib_bool_t
+ib_is_virtual_table(
+ ib_crsr_t crsr);
+
#endif /* api0api_h */
diff --git a/storage/innobase/include/btr0btr.h b/storage/innobase/include/btr0btr.h
index e350e01ff5b..c177f23824f 100644
--- a/storage/innobase/include/btr0btr.h
+++ b/storage/innobase/include/btr0btr.h
@@ -179,7 +179,7 @@ dberr_t
btr_root_adjust_on_import(
/*======================*/
const dict_index_t* index) /*!< in: index tree */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**************************************************************//**
Gets the height of the B-tree (the level of the root, when the leaf
@@ -191,7 +191,7 @@ btr_height_get(
/*===========*/
dict_index_t* index, /*!< in: index tree */
mtr_t* mtr) /*!< in/out: mini-transaction */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Gets a buffer page and declares its latching order level.
@param[in] page_id page id
@@ -254,7 +254,7 @@ index_id_t
btr_page_get_index_id(
/*==================*/
const page_t* page) /*!< in: index page */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_HOTBACKUP
/********************************************************//**
Gets the node level field in an index page.
@@ -264,7 +264,7 @@ ulint
btr_page_get_level_low(
/*===================*/
const page_t* page) /*!< in: index page */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#define btr_page_get_level(page, mtr) btr_page_get_level_low(page)
/********************************************************//**
Gets the next index page number.
@@ -275,7 +275,7 @@ btr_page_get_next(
/*==============*/
const page_t* page, /*!< in: index page */
mtr_t* mtr) /*!< in: mini-transaction handle */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************//**
Gets the previous index page number.
@return prev page number */
@@ -285,7 +285,7 @@ btr_page_get_prev(
/*==============*/
const page_t* page, /*!< in: index page */
mtr_t* mtr) /*!< in: mini-transaction handle */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**************************************************************//**
Releases the latch on a leaf page and bufferunfixes it. */
UNIV_INLINE
@@ -310,7 +310,7 @@ btr_node_ptr_get_child_page_no(
/*===========================*/
const rec_t* rec, /*!< in: node pointer record */
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Create the root node for a new index tree.
@param[in] type type of the index
@@ -374,7 +374,7 @@ btr_root_raise_and_insert(
const dtuple_t* tuple, /*!< in: tuple to insert */
ulint n_ext, /*!< in: number of externally stored columns */
mtr_t* mtr) /*!< in: mtr */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*************************************************************//**
Reorganizes an index page.
@@ -399,7 +399,7 @@ btr_page_reorganize_low(
page_cur_t* cursor, /*!< in/out: page cursor */
dict_index_t* index, /*!< in: the index tree of the page */
mtr_t* mtr) /*!< in/out: mini-transaction */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*************************************************************//**
Reorganizes an index page.
@@ -429,7 +429,7 @@ btr_page_get_split_rec_to_left(
rec_t** split_rec)/*!< out: if split recommended,
the first record on upper half page,
or NULL if tuple should be first */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*************************************************************//**
Decides if the page should be split at the convergence point of
inserts converging to right.
@@ -441,7 +441,7 @@ btr_page_get_split_rec_to_right(
rec_t** split_rec)/*!< out: if split recommended,
the first record on upper half page,
or NULL if tuple should be first */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*************************************************************//**
Splits an index page to halves and inserts the tuple. It is assumed
@@ -465,7 +465,7 @@ btr_page_split_and_insert(
const dtuple_t* tuple, /*!< in: tuple to insert */
ulint n_ext, /*!< in: number of externally stored columns */
mtr_t* mtr) /*!< in: mtr */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
Inserts a data tuple to a tree on a non-leaf level. It is assumed
that mtr holds an x-latch on the tree. */
@@ -478,8 +478,7 @@ btr_insert_on_non_leaf_level_func(
dtuple_t* tuple, /*!< in: the record to be inserted */
const char* file, /*!< in: file name */
ulint line, /*!< in: line where called */
- mtr_t* mtr) /*!< in: mtr */
- MY_ATTRIBUTE((nonnull(4,5)));
+ mtr_t* mtr); /*!< in: mtr */
# define btr_insert_on_non_leaf_level(f,i,l,t,m) \
btr_insert_on_non_leaf_level_func(f,i,l,t,__FILE__,__LINE__,m)
#endif /* !UNIV_HOTBACKUP */
@@ -511,7 +510,7 @@ btr_check_node_ptr(
dict_index_t* index, /*!< in: index tree */
buf_block_t* block, /*!< in: index page */
mtr_t* mtr) /*!< in: mtr */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */
/*************************************************************//**
Tries to merge the page first to the left immediate brother if such a
@@ -543,8 +542,7 @@ btr_discard_page(
/*=============*/
btr_cur_t* cursor, /*!< in: cursor on the page to discard: not on
the root page */
- mtr_t* mtr) /*!< in: mtr */
- MY_ATTRIBUTE((nonnull));
+ mtr_t* mtr); /*!< in: mtr */
#endif /* !UNIV_HOTBACKUP */
/****************************************************************//**
Parses the redo log record for setting an index record as the predefined
@@ -571,7 +569,7 @@ btr_parse_page_reorganize(
bool compressed,/*!< in: true if compressed page */
buf_block_t* block, /*!< in: page to be reorganized, or NULL */
mtr_t* mtr) /*!< in: mtr or NULL */
- MY_ATTRIBUTE((nonnull(1,2,3), warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_HOTBACKUP
/**************************************************************//**
Gets the number of pages in a B-tree.
@@ -583,7 +581,7 @@ btr_get_size(
ulint flag, /*!< in: BTR_N_LEAF_PAGES or BTR_TOTAL_SIZE */
mtr_t* mtr) /*!< in/out: mini-transaction where index
is s-latched */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**************************************************************//**
Gets the number of reserved and used pages in a B-tree.
@return number of pages reserved, or ULINT_UNDEFINED if the index
@@ -620,7 +618,7 @@ btr_page_alloc(
mtr_t* init_mtr) /*!< in/out: mini-transaction
for x-latching and initializing
the page */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**************************************************************//**
Frees a file page used in an index tree. NOTE: cannot free field external
storage pages because the page must contain info on its level. */
@@ -653,7 +651,7 @@ btr_page_free_low(
ulint level, /*!< in: page level (ULINT_UNDEFINED=BLOB) */
bool blob, /*!< in: blob page */
mtr_t* mtr) /*!< in: mtr */
- __attribute__((nonnull));
+ MY_ATTRIBUTE((nonnull(1,2)));
/**************************************************************//**
Gets the root node of a tree and x- or s-latches it.
@return root page, x- or s-latched */
@@ -695,7 +693,6 @@ btr_page_reorganize_block(
#ifdef UNIV_BTR_PRINT
/*************************************************************//**
Prints size info of a B-tree. */
-UNIV_INTERN
void
btr_print_size(
/*===========*/
@@ -703,7 +700,6 @@ btr_print_size(
MY_ATTRIBUTE((nonnull));
/**************************************************************//**
Prints directories and other info of all nodes in the index. */
-UNIV_INTERN
void
btr_print_index(
/*============*/
@@ -724,18 +720,17 @@ btr_index_rec_validate(
ibool dump_on_error) /*!< in: TRUE if the function
should print hex dump of record
and page on error */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**************************************************************//**
Checks the consistency of an index tree.
@return DB_SUCCESS if ok, error code if not */
-UNIV_INTERN
dberr_t
btr_validate_index(
/*===============*/
dict_index_t* index, /*!< in: index */
const trx_t* trx, /*!< in: transaction or 0 */
bool lockout)/*!< in: true if X-latch index is intended */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*************************************************************//**
Removes a page from the level list of pages. */
diff --git a/storage/innobase/include/btr0bulk.h b/storage/innobase/include/btr0bulk.h
index 64ffa89c0ae..a1887c3df2b 100644
--- a/storage/innobase/include/btr0bulk.h
+++ b/storage/innobase/include/btr0bulk.h
@@ -260,7 +260,7 @@ private:
FlushObserver* m_flush_observer;
/** Operation result DB_SUCCESS or error code */
- dberr_t m_err;
+ dberr_t m_err;
};
typedef std::vector<PageBulk*, ut_allocator<PageBulk*> >
diff --git a/storage/innobase/include/btr0sea.h b/storage/innobase/include/btr0sea.h
index 659944f327e..12659037904 100644
--- a/storage/innobase/include/btr0sea.h
+++ b/storage/innobase/include/btr0sea.h
@@ -328,6 +328,13 @@ extern rw_lock_t** btr_search_latches;
/** The adaptive hash index */
extern btr_search_sys_t* btr_search_sys;
+#ifdef UNIV_SEARCH_PERF_STAT
+/** Number of successful adaptive hash index lookups */
+extern ulint btr_search_n_succ;
+/** Number of failed adaptive hash index lookups */
+extern ulint btr_search_n_hash_fail;
+#endif /* UNIV_SEARCH_PERF_STAT */
+
/** After change in n_fields or n_bytes in info, this many rounds are waited
before starting the hash analysis again: this is to save CPU time when there
is no hope in building a hash index. */
diff --git a/storage/innobase/include/btr0sea.ic b/storage/innobase/include/btr0sea.ic
index 4fd76810ea0..5f7c39ba500 100644
--- a/storage/innobase/include/btr0sea.ic
+++ b/storage/innobase/include/btr0sea.ic
@@ -200,7 +200,8 @@ btr_get_search_latch(const dict_index_t* index)
{
ut_ad(index != NULL);
- ulint ifold = ut_fold_ulint_pair(index->id, index->space);
+ ulint ifold = ut_fold_ulint_pair(static_cast<ulint>(index->id),
+ static_cast<ulint>(index->space));
return(btr_search_latches[ifold % btr_ahi_parts]);
}
@@ -215,7 +216,8 @@ btr_get_search_table(const dict_index_t* index)
{
ut_ad(index != NULL);
- ulint ifold = ut_fold_ulint_pair(index->id, index->space);
+ ulint ifold = ut_fold_ulint_pair(static_cast<ulint>(index->id),
+ static_cast<ulint>(index->space));
return(btr_search_sys->hash_tables[ifold % btr_ahi_parts]);
}
diff --git a/storage/innobase/include/btr0types.h b/storage/innobase/include/btr0types.h
index 734b33e4221..19c21982011 100644
--- a/storage/innobase/include/btr0types.h
+++ b/storage/innobase/include/btr0types.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/include/buf0buf.h b/storage/innobase/include/buf0buf.h
index 6e147ce95c5..c4bc107044d 100644
--- a/storage/innobase/include/buf0buf.h
+++ b/storage/innobase/include/buf0buf.h
@@ -109,6 +109,9 @@ extern buf_block_t* back_block2; /*!< second block, for page reorganize */
#endif /* !UNIV_HOTBACKUP */
#endif /* !UNIV_INNOCHECKSUM */
+/** Magic value to use instead of checksums when they are disabled */
+#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
+
#ifndef UNIV_INNOCHECKSUM
/** @brief States of a control block
@see buf_page_t
@@ -679,7 +682,7 @@ ulint
buf_page_get_freed_page_clock(
/*==========================*/
const buf_page_t* bpage) /*!< in: block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Reads the freed_page_clock of a buffer block.
@return freed_page_clock */
@@ -688,7 +691,7 @@ ulint
buf_block_get_freed_page_clock(
/*===========================*/
const buf_block_t* block) /*!< in: block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Tells if a block is still close enough to the MRU end of the LRU list
@@ -834,8 +837,7 @@ buf_page_is_corrupted(
bool is_log_enabled,
FILE* log_file
#endif /* UNIV_INNOCHECKSUM */
-) __attribute__((warn_unused_result));
-
+) MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_INNOCHECKSUM
#ifndef UNIV_HOTBACKUP
/**********************************************************************//**
@@ -857,7 +859,7 @@ ulint
buf_block_get_lock_hash_val(
/*========================*/
const buf_block_t* block) /*!< in: block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
#ifdef UNIV_DEBUG
/*********************************************************************//**
Finds a block in the buffer pool that points to a
@@ -1039,7 +1041,7 @@ enum buf_page_state
buf_block_get_state(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Sets the state of a block. */
UNIV_INLINE
@@ -1064,7 +1066,7 @@ ibool
buf_page_in_file(
/*=============*/
const buf_page_t* bpage) /*!< in: pointer to control block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_HOTBACKUP
/*********************************************************************//**
Determines if a block should be on unzip_LRU list.
@@ -1074,7 +1076,7 @@ ibool
buf_page_belongs_to_unzip_LRU(
/*==========================*/
const buf_page_t* bpage) /*!< in: pointer to control block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Gets the mutex of a block.
@@ -1084,7 +1086,7 @@ BPageMutex*
buf_page_get_mutex(
/*===============*/
const buf_page_t* bpage) /*!< in: pointer to control block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Get the flush type of a page.
@@ -1094,7 +1096,7 @@ buf_flush_t
buf_page_get_flush_type(
/*====================*/
const buf_page_t* bpage) /*!< in: buffer page */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Set the flush type of a page. */
UNIV_INLINE
@@ -1121,7 +1123,7 @@ enum buf_io_fix
buf_page_get_io_fix(
/*================*/
const buf_page_t* bpage) /*!< in: pointer to the control block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Gets the io_fix state of a block.
@return io_fix state */
@@ -1130,7 +1132,7 @@ enum buf_io_fix
buf_block_get_io_fix(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Sets the io_fix state of a block. */
UNIV_INLINE
@@ -1176,7 +1178,7 @@ ibool
buf_page_can_relocate(
/*==================*/
const buf_page_t* bpage) /*!< control block being relocated */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Determine if a block has been flagged old.
@@ -1186,7 +1188,7 @@ ibool
buf_page_is_old(
/*============*/
const buf_page_t* bpage) /*!< in: control block */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Flag a block old. */
UNIV_INLINE
@@ -1203,7 +1205,7 @@ unsigned
buf_page_is_accessed(
/*=================*/
const buf_page_t* bpage) /*!< in: control block */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Flag a block accessed. */
UNIV_INLINE
@@ -1222,7 +1224,7 @@ buf_block_t*
buf_page_get_block(
/*===============*/
buf_page_t* bpage) /*!< in: control block, or NULL */
- MY_ATTRIBUTE((pure));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_DEBUG
/*********************************************************************//**
@@ -1233,7 +1235,7 @@ buf_frame_t*
buf_block_get_frame(
/*================*/
const buf_block_t* block) /*!< in: pointer to the control block */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#else /* UNIV_DEBUG */
# define buf_block_get_frame(block) (block)->frame
#endif /* UNIV_DEBUG */
@@ -1244,13 +1246,14 @@ if applicable. */
#define buf_block_get_page_zip(block) \
((block)->page.zip.data ? &(block)->page.zip : NULL)
#ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Gets the block to whose frame the pointer is pointing to.
+
+/** Get a buffer block from an adaptive hash index pointer.
+This function does not return if the block is not identified.
+@param[in] ptr pointer to within a page frame
@return pointer to block, never NULL */
buf_block_t*
-buf_block_align(
-/*============*/
- const byte* ptr); /*!< in: pointer to a frame */
+buf_block_from_ahi(const byte* ptr);
+
/********************************************************************//**
Find out if a pointer belongs to a buf_block_t. It can be a pointer to
the buf_block_t itself or a member of it
@@ -1271,18 +1274,6 @@ buf_pointer_is_block_field(
#define buf_pool_is_block_lock(l) \
buf_pointer_is_block_field((const void*)(l))
-#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
-/*********************************************************************//**
-Gets the compressed page descriptor corresponding to an uncompressed page
-if applicable.
-@return compressed page descriptor, or NULL */
-UNIV_INLINE
-const page_zip_des_t*
-buf_frame_get_page_zip(
-/*===================*/
- const byte* ptr); /*!< in: pointer to the page */
-#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
-
/** Inits a page for read to the buffer buf_pool. If the page is
(1) already in buf_pool, or
(2) if we specify to read only ibuf pages and the page is not an ibuf page, or
@@ -1322,7 +1313,7 @@ ulint
buf_pool_index(
/*===========*/
const buf_pool_t* buf_pool) /*!< in: buffer pool */
- MY_ATTRIBUTE((nonnull, const));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Returns the buffer pool instance given a page instance
@return buf_pool */
@@ -1465,7 +1456,7 @@ buf_page_t*
buf_pool_watch_set(
const page_id_t& page_id,
rw_lock_t** hash_lock)
- MY_ATTRIBUTE((warn_unused_result));
+MY_ATTRIBUTE((warn_unused_result));
/** Stop watching if the page has been read in.
buf_pool_watch_set(space,offset) must have returned NULL before.
@@ -1482,7 +1473,7 @@ has returned NULL and before invoking buf_pool_watch_unset(space,offset).
ibool
buf_pool_watch_occurred(
const page_id_t& page_id)
- MY_ATTRIBUTE((warn_unused_result));
+MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Get total buffer pool statistics. */
diff --git a/storage/innobase/include/buf0buf.ic b/storage/innobase/include/buf0buf.ic
index bd75c7a3d22..bf7799774c6 100644
--- a/storage/innobase/include/buf0buf.ic
+++ b/storage/innobase/include/buf0buf.ic
@@ -1,8 +1,8 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2014, 2015, MariaDB Corporation.
+Copyright (c) 2014, 2016, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -50,6 +50,11 @@ struct buf_chunk_t{
alloc method and later passed to the
deallocate method. */
buf_block_t* blocks; /*!< array of buffer control blocks */
+
+ /** Get the size of 'mem' in bytes. */
+ size_t mem_size() const {
+ return(mem_pfx.m_size);
+ }
};
/*********************************************************************//**
@@ -315,7 +320,8 @@ buf_page_set_state(
break;
case BUF_BLOCK_FILE_PAGE:
if (!(state == BUF_BLOCK_NOT_USED
- || state == BUF_BLOCK_REMOVE_HASH)) {
+ || state == BUF_BLOCK_REMOVE_HASH
+ || state == BUF_BLOCK_FILE_PAGE)) {
const char *old_state_name = buf_get_state_name((buf_block_t*)bpage);
bpage->state = state;
@@ -326,10 +332,11 @@ buf_page_set_state(
old_state_name,
state,
buf_get_state_name((buf_block_t*)bpage));
+ ut_a(state == BUF_BLOCK_NOT_USED
+ || state == BUF_BLOCK_REMOVE_HASH
+ || state == BUF_BLOCK_FILE_PAGE);
}
- ut_a(state == BUF_BLOCK_NOT_USED
- || state == BUF_BLOCK_REMOVE_HASH);
break;
case BUF_BLOCK_REMOVE_HASH:
ut_a(state == BUF_BLOCK_MEMORY);
@@ -770,23 +777,6 @@ buf_frame_align(
return(frame);
}
-#ifndef UNIV_HOTBACKUP
-#if defined UNIV_DEBUG || defined UNIV_ZIP_DEBUG
-/*********************************************************************//**
-Gets the compressed page descriptor corresponding to an uncompressed page
-if applicable.
-@return compressed page descriptor, or NULL */
-UNIV_INLINE
-const page_zip_des_t*
-buf_frame_get_page_zip(
-/*===================*/
- const byte* ptr) /*!< in: pointer to the page */
-{
- return(buf_block_get_page_zip(buf_block_align(ptr)));
-}
-#endif /* UNIV_DEBUG || UNIV_ZIP_DEBUG */
-#endif /* !UNIV_HOTBACKUP */
-
/**********************************************************************//**
Gets the space id, page offset, and byte offset within page of a
pointer pointing to a buffer frame containing a file page. */
@@ -1421,6 +1411,25 @@ buf_get_nth_chunk_block(
return(chunk->blocks);
}
+/********************************************************************//**
+Get buf frame. */
+UNIV_INLINE
+void *
+buf_page_get_frame(
+/*===============*/
+ const buf_page_t* bpage) /*!< in: buffer pool page */
+{
+ /* In encryption/compression buffer pool page may contain extra
+ buffer where result is stored. */
+ if (bpage->slot && bpage->slot->out_buf) {
+ return bpage->slot->out_buf;
+ } else if (bpage->zip.data) {
+ return bpage->zip.data;
+ } else {
+ return ((buf_block_t*) bpage)->frame;
+ }
+}
+
/** Verify the possibility that a stored page is not in buffer pool.
@param[in] withdraw_clock withdraw clock when stored the page
@retval true if the page might be relocated */
@@ -1452,22 +1461,4 @@ buf_pool_size_align(
}
}
-/********************************************************************//**
-Get buf frame. */
-UNIV_INLINE
-void *
-buf_page_get_frame(
-/*===============*/
- const buf_page_t* bpage) /*!< in: buffer pool page */
-{
- /* In encryption/compression buffer pool page may contain extra
- buffer where result is stored. */
- if (bpage->slot && bpage->slot->out_buf) {
- return bpage->slot->out_buf;
- } else if (bpage->zip.data) {
- return bpage->zip.data;
- } else {
- return ((buf_block_t*) bpage)->frame;
- }
-}
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/buf0checksum.h b/storage/innobase/include/buf0checksum.h
index 684c378e066..9405251dc74 100644
--- a/storage/innobase/include/buf0checksum.h
+++ b/storage/innobase/include/buf0checksum.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -30,9 +30,6 @@ Created Aug 11, 2011 Vasil Dimov
#include "buf0types.h"
-/** Magic value to use instead of checksums when they are disabled */
-#define BUF_NO_CHECKSUM_MAGIC 0xDEADBEEFUL
-
/** Calculates the CRC32 checksum of a page. The value is stored to the page
when it is written to a file and also checked for a match when reading from
the file. When reading we allow both normal CRC32 and CRC-legacy-big-endian
@@ -70,6 +67,7 @@ buf_calc_page_old_checksum(
/*=======================*/
const byte* page); /*!< in: buffer page */
+
/********************************************************************//**
Return a printable string describing the checksum algorithm.
@return algorithm name */
@@ -79,5 +77,6 @@ buf_checksum_algorithm_name(
srv_checksum_algorithm_t algo); /*!< in: algorithm */
extern ulong srv_checksum_algorithm;
+extern bool legacy_big_endian_checksum;
#endif /* buf0checksum_h */
diff --git a/storage/innobase/include/buf0dblwr.h b/storage/innobase/include/buf0dblwr.h
index 1f8f23edd4e..eb13c3b35e5 100644
--- a/storage/innobase/include/buf0dblwr.h
+++ b/storage/innobase/include/buf0dblwr.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -43,7 +43,7 @@ extern ibool buf_dblwr_being_created;
Creates the doublewrite buffer to a new InnoDB installation. The header of the
doublewrite buffer is placed on the trx system header page.
@return true if successful, false if not. */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
bool
buf_dblwr_create(void);
/*==================*/
diff --git a/storage/innobase/include/buf0flu.h b/storage/innobase/include/buf0flu.h
index 1d38c679f81..40083798d48 100644
--- a/storage/innobase/include/buf0flu.h
+++ b/storage/innobase/include/buf0flu.h
@@ -36,14 +36,18 @@ Created 11/5/1995 Heikki Tuuri
/** Flag indicating if the page_cleaner is in active state. */
extern bool buf_page_cleaner_is_active;
-/** Event to synchronise with the flushing. */
-extern os_event_t buf_flush_event;
+#ifdef UNIV_DEBUG
-class ut_stage_alter_t;
+/** Value of MySQL global variable used to disable page cleaner. */
+extern my_bool innodb_page_cleaner_disabled_debug;
+
+#endif /* UNIV_DEBUG */
/** Event to synchronise with the flushing. */
extern os_event_t buf_flush_event;
+class ut_stage_alter_t;
+
/** Handled page counters for a single flush */
struct flush_counters_t {
ulint flushed; /*!< number of dirty pages flushed */
@@ -101,7 +105,7 @@ buf_flush_page_try(
/*===============*/
buf_pool_t* buf_pool, /*!< in/out: buffer pool instance */
buf_block_t* block) /*!< in/out: buffer control block */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
# endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
/** Do flushing batch of a given type.
NOTE: The calling thread is not allowed to own any latches on pages!
@@ -124,6 +128,7 @@ buf_flush_do_batch(
lsn_t lsn_limit,
flush_counters_t* n);
+
/** This utility flushes dirty blocks from the end of the flush list of all
buffer pool instances.
NOTE: The calling thread is not allowed to own any latches on pages!
@@ -216,6 +221,22 @@ buf_flush_ready_for_replace(
/*========================*/
buf_page_t* bpage); /*!< in: buffer control block, must be
buf_page_in_file(bpage) and in the LRU list */
+
+#ifdef UNIV_DEBUG
+/** Disables page cleaner threads (coordinator and workers).
+It's used by: SET GLOBAL innodb_page_cleaner_disabled_debug = 1 (0).
+@param[in] thd thread handle
+@param[in] var pointer to system variable
+@param[out] var_ptr where the formal string goes
+@param[in] save immediate result from check function */
+void
+buf_flush_page_cleaner_disabled_debug_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save);
+#endif /* UNIV_DEBUG */
+
/******************************************************************//**
page_cleaner thread tasked with flushing dirty pages from the buffer
pools. As of now we'll have only one coordinator of this thread.
diff --git a/storage/innobase/include/buf0rea.h b/storage/innobase/include/buf0rea.h
index f2ec11f1783..9c97a5147c1 100644
--- a/storage/innobase/include/buf0rea.h
+++ b/storage/innobase/include/buf0rea.h
@@ -126,13 +126,6 @@ buf_read_ibuf_merge_pages(
to get read in, before this
function returns */
const ulint* space_ids, /*!< in: array of space ids */
- const ib_uint64_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
diff --git a/storage/innobase/include/data0data.h b/storage/innobase/include/data0data.h
index 24b0a791535..5537d70548a 100644
--- a/storage/innobase/include/data0data.h
+++ b/storage/innobase/include/data0data.h
@@ -70,8 +70,8 @@ void
dfield_set_type(
/*============*/
dfield_t* field, /*!< in: SQL data field */
- const dtype_t* type) /*!< in: pointer to data type struct */
- MY_ATTRIBUTE((nonnull));
+ const dtype_t* type); /*!< in: pointer to data type struct */
+
/*********************************************************************//**
Gets length of field data.
@return length of data; UNIV_SQL_NULL if SQL null data */
@@ -116,6 +116,23 @@ dfield_set_ext(
/*===========*/
dfield_t* field) /*!< in/out: field */
MY_ATTRIBUTE((nonnull));
+
+/** Gets spatial status for "external storage"
+@param[in,out] field field */
+UNIV_INLINE
+spatial_status_t
+dfield_get_spatial_status(
+ const dfield_t* field);
+
+/** Sets spatial status for "external storage"
+@param[in,out] field field
+@param[in] spatial_status spatial status */
+UNIV_INLINE
+void
+dfield_set_spatial_status(
+ dfield_t* field,
+ spatial_status_t spatial_status);
+
/*********************************************************************//**
Sets pointer to the data and length in a field. */
UNIV_INLINE
@@ -134,7 +151,7 @@ dfield_write_mbr(
/*=============*/
dfield_t* field, /*!< in: field */
const double* mbr) /*!< in: data */
- __attribute__((nonnull(1)));
+ MY_ATTRIBUTE((nonnull(1)));
/*********************************************************************//**
Sets a data field to SQL NULL. */
UNIV_INLINE
@@ -159,8 +176,8 @@ void
dfield_copy_data(
/*=============*/
dfield_t* field1, /*!< out: field to copy to */
- const dfield_t* field2) /*!< in: field to copy from */
- MY_ATTRIBUTE((nonnull));
+ const dfield_t* field2); /*!< in: field to copy from */
+
/*********************************************************************//**
Copies a data field to another. */
UNIV_INLINE
@@ -408,7 +425,7 @@ int
dtuple_coll_cmp(
const dtuple_t* tuple1,
const dtuple_t* tuple2)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Fold a prefix given as the number of fields of a tuple.
@param[in] tuple index record
@param[in] n_fields number of complete fields to fold
@@ -422,7 +439,7 @@ dtuple_fold(
ulint n_fields,
ulint n_bytes,
index_id_t tree_id)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Sets types of fields binary in a tuple. */
UNIV_INLINE
@@ -544,7 +561,7 @@ dtuple_convert_big_rec(
dtuple_t* entry, /*!< in/out: index entry */
ulint* n_ext) /*!< in/out: number of
externally stored columns */
- MY_ATTRIBUTE((nonnull(1,4), malloc, warn_unused_result));
+ MY_ATTRIBUTE((malloc, warn_unused_result));
/**************************************************************//**
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
@@ -572,7 +589,10 @@ dtuple_big_rec_free(
/** Structure for an SQL data field */
struct dfield_t{
void* data; /*!< pointer to data */
- unsigned ext; /*!< TRUE=externally stored, FALSE=local */
+ unsigned ext:1; /*!< TRUE=externally stored, FALSE=local */
+ unsigned spatial_status:2;
+ /*!< spatial status of externally stored field
+ in undo log for purge */
unsigned len; /*!< data length; UNIV_SQL_NULL if SQL null */
dtype_t type; /*!< type of data */
diff --git a/storage/innobase/include/data0data.ic b/storage/innobase/include/data0data.ic
index c6c155c6b61..dc51735d340 100644
--- a/storage/innobase/include/data0data.ic
+++ b/storage/innobase/include/data0data.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -157,6 +157,34 @@ dfield_set_ext(
field->ext = 1;
}
+/** Gets spatial status for "external storage"
+@param[in,out] field field */
+UNIV_INLINE
+spatial_status_t
+dfield_get_spatial_status(
+ const dfield_t* field)
+{
+ ut_ad(field);
+ ut_ad(dfield_is_ext(field));
+
+ return(static_cast<spatial_status_t>(field->spatial_status));
+}
+
+/** Sets spatial status for "external storage"
+@param[in,out] field field
+@param[in] spatial_status spatial status */
+UNIV_INLINE
+void
+dfield_set_spatial_status(
+ dfield_t* field,
+ spatial_status_t spatial_status)
+{
+ ut_ad(field);
+ ut_ad(dfield_is_ext(field));
+
+ field->spatial_status = spatial_status;
+}
+
/*********************************************************************//**
Sets pointer to the data and length in a field. */
UNIV_INLINE
@@ -227,6 +255,7 @@ dfield_copy_data(
field1->data = field2->data;
field1->len = field2->len;
field1->ext = field2->ext;
+ field1->spatial_status = field2->spatial_status;
}
/*********************************************************************//**
diff --git a/storage/innobase/include/db0err.h b/storage/innobase/include/db0err.h
index 5297d6b0daf..32f9117af84 100644
--- a/storage/innobase/include/db0err.h
+++ b/storage/innobase/include/db0err.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2015, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
@@ -137,6 +137,7 @@ enum dberr_t {
/*< Too many words in a phrase */
DB_TABLESPACE_TRUNCATED, /*!< tablespace was truncated */
+
DB_DECRYPTION_FAILED, /* Tablespace encrypted and
decrypt operation failed because
of missing key management plugin,
@@ -157,6 +158,12 @@ enum dberr_t {
DB_IO_NO_PUNCH_HOLE_TABLESPACE, /*!< The tablespace doesn't support
punch hole */
+ DB_IO_DECRYPT_FAIL, /*!< Failure to decrypt a page
+ after reading it from disk */
+
+ DB_IO_NO_ENCRYPT_TABLESPACE, /*!< The tablespace doesn't support
+ encrypt */
+
DB_IO_PARTIAL_FAILED, /*!< Partial IO request failed */
DB_FORCED_ABORT, /*!< Transaction was forced to rollback
@@ -169,6 +176,10 @@ enum dberr_t {
DB_COMPUTE_VALUE_FAILED, /*!< Compute generated value failed */
+ DB_NO_FK_ON_S_BASE_COL, /*!< Cannot add foreign constrain
+ placed on the base column of
+ stored column */
+
/* The following are partial failure codes */
DB_FAIL = 1000,
DB_OVERFLOW,
diff --git a/storage/innobase/include/dict0crea.h b/storage/innobase/include/dict0crea.h
index 7915d694c2d..f9ef39fa8c6 100644
--- a/storage/innobase/include/dict0crea.h
+++ b/storage/innobase/include/dict0crea.h
@@ -213,6 +213,20 @@ dict_create_add_foreigns_to_dictionary(
const dict_table_t* table,
trx_t* trx)
MY_ATTRIBUTE((nonnull, warn_unused_result));
+
+/** Check if a foreign constraint is on columns server as base columns
+of any stored column. This is to prevent creating SET NULL or CASCADE
+constraint on such columns
+@param[in] local_fk_set set of foreign key objects, to be added to
+the dictionary tables
+@param[in] table table to which the foreign key objects in
+local_fk_set belong to
+@return true if yes, otherwise, false */
+bool
+dict_foreigns_has_s_base_col(
+ const dict_foreign_set& local_fk_set,
+ const dict_table_t* table);
+
/****************************************************************//**
Creates the tablespaces and datafiles system tables inside InnoDB
at server bootstrap or server start if they are not found or are
diff --git a/storage/innobase/include/dict0defrag_bg.h b/storage/innobase/include/dict0defrag_bg.h
new file mode 100644
index 00000000000..eb2a6e6824f
--- /dev/null
+++ b/storage/innobase/include/dict0defrag_bg.h
@@ -0,0 +1,93 @@
+/*****************************************************************************
+
+Copyright (c) 2016, MariaDB Corporation. All rights Reserved.
+
+This program is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free Software
+Foundation; version 2 of the License.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along with
+this program; if not, write to the Free Software Foundation, Inc.,
+51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
+
+*****************************************************************************/
+
+/**************************************************//**
+@file include/dict0defrag_bg.h
+Code used for background table and index
+defragmentation
+
+Created 25/08/2016 Jan Lindström
+*******************************************************/
+
+#ifndef dict0defrag_bg_h
+#define dict0defrag_bg_h
+
+#include "univ.i"
+
+#include "dict0types.h"
+#include "os0event.h"
+#include "os0thread.h"
+
+/*****************************************************************//**
+Initialize the defrag pool, called once during thread initialization. */
+void
+dict_defrag_pool_init(void);
+/*========================*/
+
+/*****************************************************************//**
+Free the resources occupied by the defrag pool, called once during
+thread de-initialization. */
+void
+dict_defrag_pool_deinit(void);
+/*==========================*/
+
+/*****************************************************************//**
+Add an index in a table to the defrag pool, which is processed by the
+background stats gathering thread. Only the table id and index id are
+added to the list, so the table can be closed after being enqueued and
+it will be opened when needed. If the table or index does not exist later
+(has been DROPped), then it will be removed from the pool and skipped. */
+void
+dict_stats_defrag_pool_add(
+/*=======================*/
+ const dict_index_t* index); /*!< in: table to add */
+
+/*****************************************************************//**
+Delete a given index from the auto defrag pool. */
+void
+dict_stats_defrag_pool_del(
+/*=======================*/
+ const dict_table_t* table, /*!<in: if given, remove
+ all entries for the table */
+ const dict_index_t* index); /*!< in: index to remove */
+
+/*****************************************************************//**
+Get the first index that has been added for updating persistent defrag
+stats and eventually save its stats. */
+void
+dict_defrag_process_entries_from_defrag_pool();
+/*===========================================*/
+
+/*********************************************************************//**
+Save defragmentation result.
+@return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_summary(
+/*============================*/
+ dict_index_t* index) /*!< in: index */
+ MY_ATTRIBUTE((warn_unused_result));
+
+/*********************************************************************//**
+Save defragmentation stats for a given index.
+@return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_defrag_stats(
+/*============================*/
+ dict_index_t* index) /*!< in: index */
+ MY_ATTRIBUTE((warn_unused_result));
+#endif /* dict0defrag_bg_h */
diff --git a/storage/innobase/include/dict0dict.h b/storage/innobase/include/dict0dict.h
index af7b91f9662..5022245c195 100644
--- a/storage/innobase/include/dict0dict.h
+++ b/storage/innobase/include/dict0dict.h
@@ -125,7 +125,7 @@ dict_table_open_on_id(
table_id_t table_id, /*!< in: table id */
ibool dict_locked, /*!< in: TRUE=data dictionary locked */
dict_table_op_t table_op) /*!< in: operation to perform */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Returns a table object based on table id.
@@ -309,7 +309,7 @@ ulint
dict_col_get_index_pos(
const dict_col_t* col,
const dict_index_t* index)
- __attribute__((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
/****************************************************************//**
If the given column name is reserved for InnoDB system columns, return
@@ -389,7 +389,7 @@ dict_table_add_system_columns(
void
dict_table_set_big_rows(
dict_table_t* table)
- __attribute__((nonnull));
+ MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Adds a table object to the dictionary cache. */
void
@@ -531,7 +531,7 @@ dict_create_foreign_constraints(
size_t sql_length,
const char* name,
ibool reject_fks)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Parses the CONSTRAINT id's to be dropped in an ALTER TABLE statement.
@return DB_SUCCESS or DB_CANNOT_DROP_CONSTRAINT if syntax error or the
@@ -565,7 +565,7 @@ dict_table_open_on_name(
ibool dict_locked,
ibool try_drop,
dict_err_ignore_t ignore_err)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Tries to find an index whose first fields are the columns in the array,
@@ -598,7 +598,7 @@ dict_foreign_find_index(
/*!< out: column number where
error happened */
dict_index_t** err_index)
- /*!< out: index where error
+ /*!< out: index where error
happened */
MY_ATTRIBUTE((nonnull(1,3), warn_unused_result));
@@ -624,7 +624,7 @@ dict_table_get_col_name_for_mysql(
const dict_table_t* table, /*!< in: table */
const char* col_name)/*!< in: MySQL table column name */
MY_ATTRIBUTE((nonnull, warn_unused_result));
-
+
/** Returns a virtual column's name.
@param[in] table table object
@param[in] col_nr virtual column number(nth virtual column)
@@ -634,7 +634,8 @@ dict_table_get_v_col_name(
const dict_table_t* table,
ulint col_nr);
-/**********************************************************************//**
+/** Check if the table has a given column.
+@param[in] table table object
@param[in] col_name column name
@param[in] col_nr column number guessed, 0 as default
@return column number if the table has the specified column,
@@ -656,6 +657,7 @@ dict_print_info_on_foreign_keys(
of SHOW TABLE STATUS */
trx_t* trx, /*!< in: transaction */
dict_table_t* table); /*!< in: table */
+
/**********************************************************************//**
Outputs info on a foreign key of a table in a format suitable for
CREATE TABLE. */
@@ -665,6 +667,7 @@ dict_print_info_on_foreign_key_in_create_format(
trx_t* trx, /*!< in: transaction */
dict_foreign_t* foreign, /*!< in: foreign key constraint */
ibool add_newline); /*!< in: whether to add a newline */
+
/*********************************************************************//**
Tries to find an index whose first fields are the columns in the array,
in the same order and is not marked for deletion and is not the same
@@ -756,7 +759,7 @@ ulint
dict_index_is_clust(
/*================*/
const dict_index_t* index) /*!< in: index */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Check if index is auto-generated clustered index.
@param[in] index index
@@ -775,7 +778,7 @@ ulint
dict_index_is_unique(
/*=================*/
const dict_index_t* index) /*!< in: index */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Check whether the index is a Spatial Index.
@return nonzero for Spatial Index, zero for other indexes */
@@ -784,7 +787,7 @@ ulint
dict_index_is_spatial(
/*==================*/
const dict_index_t* index) /*!< in: index */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Check whether the index contains a virtual column.
@param[in] index index
@return nonzero for index on virtual column, zero for other indexes */
@@ -800,7 +803,7 @@ ulint
dict_index_is_ibuf(
/*===============*/
const dict_index_t* index) /*!< in: index */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Check whether the index is a secondary index or the insert buffer tree.
@return nonzero for insert buffer, zero for other indexes */
@@ -809,7 +812,7 @@ ulint
dict_index_is_sec_or_ibuf(
/*======================*/
const dict_index_t* index) /*!< in: index */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Get all the FTS indexes on a table.
@param[in] table table
@@ -830,7 +833,7 @@ ulint
dict_table_get_n_user_cols(
/*=======================*/
const dict_table_t* table) /*!< in: table */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Gets the number of user-defined virtual and non-virtual columns in a table
in the dictionary cache.
@param[in] table table
@@ -849,7 +852,7 @@ ulint
dict_table_get_n_sys_cols(
/*======================*/
const dict_table_t* table) /*!< in: table */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Gets the number of all non-virtual columns (also system) in a table
in the dictionary cache.
@@ -859,7 +862,7 @@ ulint
dict_table_get_n_cols(
/*==================*/
const dict_table_t* table) /*!< in: table */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Gets the number of virtual columns in a table in the dictionary cache.
@param[in] table the table to check
@@ -885,7 +888,7 @@ ib_uint64_t
dict_table_get_n_rows(
/*==================*/
const dict_table_t* table) /*!< in: table */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Increment the number of rows in the table by one.
Notice that this operation is not protected by any latch, the number is
@@ -1005,6 +1008,7 @@ dict_tf_get_format(
/*===============*/
ulint flags) /*!< in: dict_table_t::flags */
MY_ATTRIBUTE((warn_unused_result));
+
/** Set the various values in a dict_table_t::flags pointer.
@param[in,out] flags, Pointer to a 4 byte Table Flags
@param[in] format, File Format
@@ -1053,11 +1057,13 @@ fil_space_t::flags | 0 | 0 | 1 | 1
==================================================================
@param[in] table_flags dict_table_t::flags
@param[in] is_temp whether the tablespace is temporary
+@param[in] is_encrypted whether the tablespace is encrypted
@return tablespace flags (fil_space_t::flags) */
ulint
dict_tf_to_fsp_flags(
ulint table_flags,
- bool is_temp)
+ bool is_temp,
+ bool is_encrypted = false)
MY_ATTRIBUTE((const));
/** Extract the page size from table flags.
@@ -1067,7 +1073,7 @@ UNIV_INLINE
const page_size_t
dict_tf_get_page_size(
ulint flags)
-__attribute__((const));
+MY_ATTRIBUTE((const));
/** Determine the extent size (in pages) for the given table
@param[in] table the table whose extent size is being
@@ -1084,7 +1090,7 @@ UNIV_INLINE
const page_size_t
dict_table_page_size(
const dict_table_t* table)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_HOTBACKUP
/*********************************************************************//**
@@ -1194,7 +1200,7 @@ dict_index_add_to_cache(
dict_index_t* index,
ulint page_no,
ibool strict)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Adds an index to the dictionary cache, with possible indexing newly
added column.
@@ -1215,7 +1221,7 @@ dict_index_add_to_cache_w_vcol(
const dict_add_v_col_t* add_v,
ulint page_no,
ibool strict)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
/********************************************************************//**
Gets the number of fields in the internal representation of an index,
@@ -1269,7 +1275,7 @@ UNIV_INLINE
ulint
dict_index_get_n_unique_in_tree_nonleaf(
const dict_index_t* index)
- __attribute__((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
/********************************************************************//**
Gets the number of user-defined ordering fields in the index. In the internal
representation we add the row id to the ordering fields to make all indexes
@@ -1327,9 +1333,9 @@ dict_index_get_nth_col_pos(
/*=======================*/
const dict_index_t* index, /*!< in: index */
ulint n, /*!< in: column number */
- ulint* prefix_col_pos) /*!< out: col num if prefix
- */
- __attribute__((warn_unused_result));
+ ulint* prefix_col_pos) /*!< out: col num if prefix */
+ MY_ATTRIBUTE((nonnull(1), warn_unused_result));
+
/** Looks for column n in an index.
@param[in] index index
@param[in] n column number
@@ -1362,7 +1368,7 @@ dict_index_contains_col_or_prefix(
ulint n, /*!< in: column number */
bool is_virtual)
/*!< in: whether it is a virtual col */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Looks for a matching field in an index. The column has to be the same. The
column in index must be complete, or must contain a prefix longer than the
@@ -1386,7 +1392,7 @@ dict_table_get_nth_col_pos(
const dict_table_t* table, /*!< in: table */
ulint n, /*!< in: column number */
ulint* prefix_col_pos) /*!< out: col num if prefix */
- __attribute__((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/********************************************************************//**
Returns the position of a system column in an index.
@return position, ULINT_UNDEFINED if not contained */
@@ -1668,6 +1674,7 @@ dict_tables_have_same_db(
const char* name2) /*!< in: table name in the form
dbname '/' tablename */
MY_ATTRIBUTE((nonnull, warn_unused_result));
+
/** Get an index by name.
@param[in] table the table where to look for the index
@param[in] name the index name to look for
@@ -1679,19 +1686,13 @@ dict_table_get_index_on_name(
dict_table_t* table,
const char* name,
bool committed=true)
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
+
/** Get an index by name.
@param[in] table the table where to look for the index
@param[in] name the index name to look for
@param[in] committed true=search for committed,
-false=search for uncommitted */
-dict_index_t*
-dict_table_find_index_on_id(
-/*========================*/
- const dict_table_t* table, /*!< in: table instance */
- index_id_t id) /*!< in: index id */
- __attribute__((nonnull, warn_unused_result));
-/**********************************************************************//**
+false=search for uncommitted
@return index, NULL if does not exist */
inline
const dict_index_t*
@@ -1715,7 +1716,7 @@ dict_table_is_fts_column(
ib_vector_t* indexes,/* in: vector containing only FTS indexes */
ulint col_no, /* in: col number to search for */
bool is_virtual)/*!< in: whether it is a virtual column */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Prevent table eviction by moving a table to the non-LRU list from the
LRU list if it is not already there. */
@@ -1724,7 +1725,8 @@ void
dict_table_prevent_eviction(
/*========================*/
dict_table_t* table) /*!< in: table to prevent eviction */
- __attribute__((nonnull));
+ MY_ATTRIBUTE((nonnull));
+
/**********************************************************************//**
Move a table to the non LRU end of the LRU list. */
void
@@ -1732,6 +1734,7 @@ dict_table_move_from_lru_to_non_lru(
/*================================*/
dict_table_t* table) /*!< in: table to move from LRU to non-LRU */
MY_ATTRIBUTE((nonnull));
+
/** Looks for an index with the given id given a table instance.
@param[in] table table instance
@param[in] id index id
@@ -1741,6 +1744,7 @@ dict_table_find_index_on_id(
const dict_table_t* table,
index_id_t id)
MY_ATTRIBUTE((nonnull(1)));
+
/**********************************************************************//**
Move to the most recently used segment of the LRU list. */
void
@@ -1990,7 +1994,7 @@ bool
dict_table_is_discarded(
/*====================*/
const dict_table_t* table) /*!< in: table to check */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Check if it is a temporary table.
@@ -2000,7 +2004,17 @@ bool
dict_table_is_temporary(
/*====================*/
const dict_table_t* table) /*!< in: table to check */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
+
+/********************************************************************//**
+Check if it is a encrypted table.
+@return true if table encryption flag is set. */
+UNIV_INLINE
+bool
+dict_table_is_encrypted(
+/*====================*/
+ const dict_table_t* table) /*!< in: table to check */
+ MY_ATTRIBUTE((warn_unused_result));
/** Check whether the table is intrinsic.
An intrinsic table is a special kind of temporary table that
@@ -2018,7 +2032,16 @@ UNIV_INLINE
bool
dict_table_is_intrinsic(
const dict_table_t* table)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
+
+/** Check if the table is in a shared tablespace (System or General).
+@param[in] id Space ID to check
+@return true if id is a shared tablespace, false if not. */
+UNIV_INLINE
+bool
+dict_table_in_shared_tablespace(
+ const dict_table_t* table)
+ MY_ATTRIBUTE((warn_unused_result));
/** Check whether locking is disabled for this table.
Currently this is done for intrinsic table as their visibility is limited
@@ -2030,7 +2053,7 @@ UNIV_INLINE
bool
dict_table_is_locking_disabled(
const dict_table_t* table)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Turn-off redo-logging if temporary table. */
@@ -2105,7 +2128,7 @@ ulint
dict_index_node_ptr_max_size(
/*=========================*/
const dict_index_t* index) /*!< in: index */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*****************************************************************//**
Get index by first field of the index
@return index which is having first field matches
@@ -2149,12 +2172,34 @@ dict_table_decode_n_col(
ulint* n_v_col);
/** Look for any dictionary objects that are found in the given tablespace.
-@param[in] space Tablespace ID to search for.
+@param[in] space_id Tablespace ID to search for.
@return true if tablespace is empty. */
bool
-dict_tablespace_is_empty(
+dict_space_is_empty(
ulint space_id);
+/** Find the space_id for the given name in sys_tablespaces.
+@param[in] name Tablespace name to search for.
+@return the tablespace ID. */
+ulint
+dict_space_get_id(
+ const char* name);
+
+/** Free the virtual column template
+@param[in,out] vc_templ virtual column template */
+UNIV_INLINE
+void
+dict_free_vc_templ(
+ dict_vcol_templ_t* vc_templ);
+
+/** Check whether the table have virtual index.
+@param[in] table InnoDB table
+@return true if the table have virtual index, false otherwise. */
+UNIV_INLINE
+bool
+dict_table_have_virtual_index(
+ dict_table_t* table);
+
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/dict0dict.ic b/storage/innobase/include/dict0dict.ic
index 9aa25b0a9c5..1a038d4f104 100644
--- a/storage/innobase/include/dict0dict.ic
+++ b/storage/innobase/include/dict0dict.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2016, Oracle and/or its affiliates
+Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2016, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under
@@ -338,6 +338,21 @@ dict_index_is_unique(
}
/********************************************************************//**
+Check whether the index is an universal index tree.
+@return nonzero for universal tree, zero for other indexes */
+UNIV_INLINE
+ulint
+dict_index_is_univ(
+/*===============*/
+ const dict_index_t* index) /*!< in: index */
+{
+ ut_ad(index);
+ ut_ad(index->magic_n == DICT_INDEX_MAGIC_N);
+
+ return(index->type & DICT_UNIVERSAL);
+}
+
+/********************************************************************//**
Check whether the index is a Spatial Index.
@return nonzero for Spatial Index, zero for other indexes */
UNIV_INLINE
@@ -711,7 +726,7 @@ dict_tf_is_valid(
}
}
- if (page_compression || page_compression_level) {
+ if (page_compression || page_compression_level) {
/* Page compression format must have compact and
atomic_blobs and page_compression_level requires
page_compression */
@@ -774,6 +789,7 @@ dict_tf2_is_valid(
bool file_per_table = ((flags2 & DICT_TF2_USE_FILE_PER_TABLE) != 0);
bool shared_space = DICT_TF_HAS_SHARED_SPACE(flags);
+
if (file_per_table && shared_space) {
return(false);
}
@@ -869,13 +885,13 @@ dict_sys_tables_type_validate(
format, so the DATA_DIR flag is compatible with any other
table flags. However, it is not used with TEMPORARY tables. */
- if (page_compression || page_compression_level) {
+ if (page_compression || page_compression_level) {
/* page compressed row format must have low_order_bit and
atomic_blobs bits set and the DICT_N_COLS_COMPACT flag
should be in N_COLS, but we already know about the
low_order_bit and DICT_N_COLS_COMPACT flags. */
- if (!atomic_blobs || !page_compression) {
+ if (!atomic_blobs || !page_compression) {
ib::error() << "SYS_TABLES::TYPE=" << type
<< " page_compression:" << page_compression
<< " page_compression_level:" << page_compression_level
@@ -1008,7 +1024,7 @@ dict_tf_set(
if (page_compressed) {
*flags |= (1 << DICT_TF_POS_ATOMIC_BLOBS)
- | (1 << DICT_TF_POS_PAGE_COMPRESSION)
+ | (1 << DICT_TF_POS_PAGE_COMPRESSION)
| (page_compression_level << DICT_TF_POS_PAGE_COMPRESSION_LEVEL);
ut_ad(zip_ssize == 0);
@@ -1067,7 +1083,7 @@ dict_tf_init(
if (page_compressed) {
flags |= (1 << DICT_TF_POS_ATOMIC_BLOBS)
- | (1 << DICT_TF_POS_PAGE_COMPRESSION)
+ | (1 << DICT_TF_POS_PAGE_COMPRESSION)
| (page_compression_level << DICT_TF_POS_PAGE_COMPRESSION_LEVEL);
ut_ad(zip_ssize == 0);
@@ -1706,9 +1722,11 @@ dict_max_v_field_len_store_undo(
for UNIV_FORMAT_B, upto col->max_prefix or
2) REC_VERSION_56_MAX_INDEX_COL_LEN, whichever is less */
if (dict_table_get_format(table) >= UNIV_FORMAT_B) {
- max_log_len = (col->max_prefix > 0)
- ? col->max_prefix
- : DICT_MAX_FIELD_LEN_BY_FORMAT(table);
+ if (DATA_BIG_COL(col) && col->max_prefix > 0) {
+ max_log_len = col->max_prefix;
+ } else {
+ max_log_len = DICT_MAX_FIELD_LEN_BY_FORMAT(table);
+ }
} else {
max_log_len = REC_ANTELOPE_MAX_INDEX_COL_LEN;
}
@@ -1786,6 +1804,18 @@ dict_table_is_temporary(
return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_TEMPORARY));
}
+/********************************************************************//**
+Check if it is a encrypted table.
+@return true if table encrypted flag is set. */
+UNIV_INLINE
+bool
+dict_table_is_encrypted(
+/*====================*/
+ const dict_table_t* table) /*!< in: table to check */
+{
+ return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_ENCRYPTION));
+}
+
/** Check whether the table is intrinsic.
An intrinsic table is a special kind of temporary table that
is invisible to the end user. It can be created internally by InnoDB, the MySQL
@@ -1806,6 +1836,18 @@ dict_table_is_intrinsic(
return(DICT_TF2_FLAG_IS_SET(table, DICT_TF2_INTRINSIC));
}
+/** Check if the table is in a shared tablespace (System or General).
+@param[in] id Space ID to check
+@return true if id is a shared tablespace, false if not. */
+UNIV_INLINE
+bool
+dict_table_in_shared_tablespace(
+ const dict_table_t* table)
+{
+ return(is_system_tablespace(table->space)
+ || DICT_TF_HAS_SHARED_SPACE(table->flags));
+}
+
/** Check whether locking is disabled for this table.
Currently this is done for intrinsic table as their visibility is limited
to the connection only.
@@ -2003,4 +2045,45 @@ dict_table_decode_n_col(
*n_col = num & 0xFFFF;
}
+/** Free the virtual column template
+@param[in,out] vc_templ virtual column template */
+void
+dict_free_vc_templ(
+ dict_vcol_templ_t* vc_templ)
+{
+ if (vc_templ->vtempl != NULL) {
+ ut_ad(vc_templ->n_v_col > 0);
+ for (ulint i = 0; i < vc_templ->n_col
+ + vc_templ->n_v_col; i++) {
+ if (vc_templ->vtempl[i] != NULL) {
+ ut_free(vc_templ->vtempl[i]);
+ }
+ }
+ ut_free(vc_templ->default_rec);
+ ut_free(vc_templ->vtempl);
+ vc_templ->vtempl = NULL;
+ }
+}
+
+/** Check whether the table have virtual index.
+@param[in] table InnoDB table
+@return true if the table have virtual index, false otherwise. */
+UNIV_INLINE
+bool
+dict_table_have_virtual_index(
+ dict_table_t* table)
+{
+ for (ulint col_no = 0; col_no < dict_table_get_n_v_cols(table);
+ col_no++) {
+ const dict_v_col_t* col
+ = dict_table_get_nth_v_col(table, col_no);
+
+ if (col->m_col.ord_part) {
+ return(true);
+ }
+ }
+
+ return(false);
+}
+
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/dict0load.h b/storage/innobase/include/dict0load.h
index 8e62022de85..6d01c38c432 100644
--- a/storage/innobase/include/dict0load.h
+++ b/storage/innobase/include/dict0load.h
@@ -184,6 +184,14 @@ dict_save_data_dir_path(
dict_table_t* table, /*!< in/out: table */
char* filepath); /*!< in: filepath of tablespace */
+/** Get the first filepath from SYS_DATAFILES for a given space_id.
+@param[in] space_id Tablespace ID
+@return First filepath (caller must invoke ut_free() on it)
+@retval NULL if no SYS_DATAFILES entry was found. */
+char*
+dict_get_first_path(
+ ulint space_id);
+
/** Make sure the data_file_name is saved in dict_table_t if needed.
Try to read it from the fil_system first, then from SYS_DATAFILES.
@param[in] table Table object
@@ -262,7 +270,7 @@ dict_load_foreigns(
which must be loaded
subsequently to load all the
foreign key constraints. */
- __attribute__((nonnull(1), warn_unused_result));
+ MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/********************************************************************//**
This function opens a system table, and return the first record.
diff --git a/storage/innobase/include/dict0mem.h b/storage/innobase/include/dict0mem.h
index 98ce7d3bd33..4fac0648bcb 100644
--- a/storage/innobase/include/dict0mem.h
+++ b/storage/innobase/include/dict0mem.h
@@ -49,6 +49,8 @@ Created 1/8/1996 Heikki Tuuri
#include "buf0buf.h"
#include "gis0type.h"
#include "os0once.h"
+#include "ut0new.h"
+
#include "fil0fil.h"
#include <my_crypt.h>
#include "fil0crypt.h"
@@ -67,6 +69,8 @@ combination of types */
auto-generated clustered indexes,
also DICT_UNIQUE will be set */
#define DICT_UNIQUE 2 /*!< unique index */
+#define DICT_UNIVERSAL 4 /*!< index which can contain records from any
+ other index */
#define DICT_IBUF 8 /*!< insert buffer tree */
#define DICT_CORRUPT 16 /*!< bit to store the corrupted flag
in SYS_INDEXES.TYPE */
@@ -170,9 +174,9 @@ DEFAULT=0, ON = 1, OFF = 2
+ DICT_TF_WIDTH_SHARED_SPACE \
+ DICT_TF_WIDTH_PAGE_COMPRESSION \
+ DICT_TF_WIDTH_PAGE_COMPRESSION_LEVEL \
- + DICT_TF_WIDTH_ATOMIC_WRITES \
- + DICT_TF_WIDTH_PAGE_ENCRYPTION \
- + DICT_TF_WIDTH_PAGE_ENCRYPTION_KEY)
+ + DICT_TF_WIDTH_ATOMIC_WRITES \
+ + DICT_TF_WIDTH_PAGE_ENCRYPTION \
+ + DICT_TF_WIDTH_PAGE_ENCRYPTION_KEY)
/** A mask of all the known/used bits in table flags */
#define DICT_TF_BIT_MASK (~(~0 << DICT_TF_BITS))
@@ -305,7 +309,7 @@ ROW_FORMAT=REDUNDANT. InnoDB engines do not check these flags
for unknown bits in order to protect backward incompatibility. */
/* @{ */
/** Total number of bits in table->flags2. */
-#define DICT_TF2_BITS 8
+#define DICT_TF2_BITS 9
#define DICT_TF2_UNUSED_BIT_MASK (~0U << DICT_TF2_BITS)
#define DICT_TF2_BIT_MASK ~DICT_TF2_UNUSED_BIT_MASK
@@ -339,6 +343,9 @@ FTS, etc.... Intrinsic table has all the properties of the normal table except
it is not created by user and so not visible to end-user. */
#define DICT_TF2_INTRINSIC 128
+/** Encryption table bit. */
+#define DICT_TF2_ENCRYPTION 256
+
/* @} */
#define DICT_TF2_FLAG_SET(table, flag) \
@@ -431,13 +438,22 @@ dict_mem_table_add_v_col(
ulint len,
ulint pos,
ulint num_base);
+
+/** Adds a stored column definition to a table.
+@param[in] table table
+@param[in] num_base number of base columns. */
+void
+dict_mem_table_add_s_col(
+ dict_table_t* table,
+ ulint num_base);
+
/**********************************************************************//**
Renames a column of a table in the data dictionary cache. */
void
dict_mem_table_col_rename(
/*======================*/
dict_table_t* table, /*!< in/out: table */
- unsigned nth_col,/*!< in: column index */
+ ulint nth_col,/*!< in: column index */
const char* from, /*!< in: old column name */
const char* to, /*!< in: new column name */
bool is_virtual);
@@ -532,6 +548,27 @@ dict_mem_referenced_table_name_lookup_set(
dict_foreign_t* foreign, /*!< in/out: foreign struct */
ibool do_alloc); /*!< in: is an alloc needed */
+/** Fills the dependent virtual columns in a set.
+Reason for being dependent are
+1) FK can be present on base column of virtual columns
+2) FK can be present on column which is a part of virtual index
+@param[in,out] foreign foreign key information. */
+void
+dict_mem_foreign_fill_vcol_set(
+ dict_foreign_t* foreign);
+
+/** Fill virtual columns set in each fk constraint present in the table.
+@param[in,out] table innodb table object. */
+void
+dict_mem_table_fill_foreign_vcol_set(
+ dict_table_t* table);
+
+/** Free the vcol_set from all foreign key constraint on the table.
+@param[in,out] table innodb table object. */
+void
+dict_mem_table_free_foreign_vcol_set(
+ dict_table_t* table);
+
/** Create a temporary tablename like "#sql-ibtid-inc where
tid = the Table ID
inc = a randomly initialized number that is incremented for each file
@@ -696,6 +733,21 @@ struct dict_add_v_col_t{
const char** v_col_name;
};
+/** Data structure for a stored column in a table. */
+struct dict_s_col_t {
+ /** Stored column ptr */
+ dict_col_t* m_col;
+ /** array of base col ptr */
+ dict_col_t** base_col;
+ /** number of base columns */
+ ulint num_base;
+ /** column pos in table */
+ ulint s_pos;
+};
+
+/** list to put stored column for create_table_info_t */
+typedef std::list<dict_s_col_t, ut_allocator<dict_s_col_t> > dict_s_col_list;
+
/** @brief DICT_ANTELOPE_MAX_INDEX_COL_LEN is measured in bytes and
is the maximum indexed column length (or indexed prefix length) in
ROW_FORMAT=REDUNDANT and ROW_FORMAT=COMPACT. Also, in any format,
@@ -726,6 +778,7 @@ be REC_VERSION_56_MAX_INDEX_COL_LEN (3072) bytes */
/** Defines the maximum fixed length column size */
#define DICT_MAX_FIXED_COL_LEN DICT_ANTELOPE_MAX_INDEX_COL_LEN
+
#ifdef WITH_WSREP
#define WSREP_MAX_SUPPORTED_KEY_LENGTH 3500
#endif /* WITH_WSREP */
@@ -982,6 +1035,9 @@ struct dict_index_t{
parser; /*!< fulltext parser plugin */
bool is_ngram;
/*!< true if it's ngram parser */
+ bool has_new_v_col;
+ /*!< whether it has a newly added virtual
+ column in ALTER */
#ifndef UNIV_HOTBACKUP
UT_LIST_NODE_T(dict_index_t)
indexes;/*!< list of indexes of the table */
@@ -1106,6 +1162,11 @@ enum online_index_status {
ONLINE_INDEX_ABORTED_DROPPED
};
+/** Set to store the virtual columns which are affected by Foreign
+key constraint. */
+typedef std::set<dict_v_col_t*, std::less<dict_v_col_t*>,
+ ut_allocator<dict_v_col_t*> > dict_vcol_set;
+
/** Data structure for a foreign key constraint; an example:
FOREIGN KEY (A, B) REFERENCES TABLE2 (C, D). Most fields will be
initialized to 0, NULL or FALSE in dict_mem_foreign_create(). */
@@ -1141,6 +1202,9 @@ struct dict_foreign_t{
does not generate new indexes
implicitly */
dict_index_t* referenced_index;/*!< referenced index */
+
+ dict_vcol_set* v_cols; /*!< set of virtual columns affected
+ by foreign key constraint. */
};
std::ostream&
@@ -1189,6 +1253,24 @@ struct dict_foreign_with_index {
const dict_index_t* m_index;
};
+#ifdef WITH_WSREP
+/** A function object to find a foreign key with the given index as the
+foreign index. Return the foreign key with matching criteria or NULL */
+struct dict_foreign_with_foreign_index {
+
+ dict_foreign_with_foreign_index(const dict_index_t* index)
+ : m_index(index)
+ {}
+
+ bool operator()(const dict_foreign_t* foreign) const
+ {
+ return(foreign->foreign_index == m_index);
+ }
+
+ const dict_index_t* m_index;
+};
+#endif
+
/* A function object to check if the foreign constraint is between different
tables. Returns true if foreign key constraint is between different tables,
false otherwise. */
@@ -1273,6 +1355,10 @@ dict_foreign_free(
/*==============*/
dict_foreign_t* foreign) /*!< in, own: foreign key struct */
{
+ if (foreign->v_cols != NULL) {
+ UT_DELETE(foreign->v_cols);
+ }
+
mem_heap_free(foreign->heap);
}
@@ -1332,12 +1418,42 @@ generate a specific template for it. */
typedef ut_list_base<lock_t, ut_list_node<lock_t> lock_table_t::*>
table_lock_list_t;
+/** mysql template structure defined in row0mysql.cc */
+struct mysql_row_templ_t;
+
+/** Structure defines template related to virtual columns and
+their base columns */
+struct dict_vcol_templ_t {
+ /** number of regular columns */
+ ulint n_col;
+
+ /** number of virtual columns */
+ ulint n_v_col;
+
+ /** array of templates for virtual col and their base columns */
+ mysql_row_templ_t** vtempl;
+
+ /** table's database name */
+ std::string db_name;
+
+ /** table name */
+ std::string tb_name;
+
+ /** share->table_name */
+ std::string share_name;
+
+ /** MySQL record length */
+ ulint rec_len;
+
+ /** default column value if any */
+ byte* default_rec;
+};
+
/* This flag is for sync SQL DDL and memcached DML.
if table->memcached_sync_count == DICT_TABLE_IN_DDL means there's DDL running on
the table, DML from memcached will be blocked. */
#define DICT_TABLE_IN_DDL -1
-struct innodb_col_templ_t;
/** These are used when MySQL FRM and InnoDB data dictionary are
in inconsistent state. */
typedef enum {
@@ -1363,6 +1479,7 @@ struct dict_table_t {
void* thd; /*!< thd */
fil_space_crypt_t *crypt_data; /*!< crypt data if present */
+
/** Release the table handle. */
inline void release();
@@ -1417,6 +1534,8 @@ struct dict_table_t {
5 whether the table is being created its own tablespace,
6 whether the table has been DISCARDed,
7 whether the aux FTS tables names are in hex.
+ 8 whether the table is instinc table.
+ 9 whether the table has encryption setting.
Use DICT_TF2_FLAG_IS_SET() to parse this flag. */
unsigned flags2:DICT_TF2_BITS;
@@ -1470,6 +1589,13 @@ struct dict_table_t {
/** Array of virtual column descriptions. */
dict_v_col_t* v_cols;
+ /** List of stored column descriptions. It is used only for foreign key
+ check during create table and copy alter operations.
+ During copy alter, s_cols list is filled during create table operation
+ and need to preserve till rename table operation. That is the
+ reason s_cols is a part of dict_table_t */
+ dict_s_col_list* s_cols;
+
/** Column names packed in a character string
"name1\0name2\0...nameN\0". Until the string contains n_cols, it will
be allocated from a temporary heap. The final string will be allocated
@@ -1650,15 +1776,22 @@ struct dict_table_t {
/** The state of the background stats thread wrt this table.
See BG_STAT_NONE, BG_STAT_IN_PROGRESS and BG_STAT_SHOULD_QUIT.
Writes are covered by dict_sys->mutex. Dirty reads are possible. */
-#define BG_SCRUB_IN_PROGRESS ((byte)(1 << 2))
+
+ #define BG_SCRUB_IN_PROGRESS ((byte)(1 << 2))
/*!< BG_SCRUB_IN_PROGRESS is set in
stats_bg_flag when the background
scrub code is working on this table. The DROP
TABLE code waits for this to be cleared
before proceeding. */
-#define BG_IN_PROGRESS (BG_STAT_IN_PROGRESS | BG_SCRUB_IN_PROGRESS)
+ #define BG_STAT_SHOULD_QUIT (1 << 1)
+
+ #define BG_IN_PROGRESS (BG_STAT_IN_PROGRESS | BG_SCRUB_IN_PROGRESS)
+
+ /** The state of the background stats thread wrt this table.
+ See BG_STAT_NONE, BG_STAT_IN_PROGRESS and BG_STAT_SHOULD_QUIT.
+ Writes are covered by dict_sys->mutex. Dirty reads are possible. */
byte stats_bg_flag;
bool stats_error_printed;
@@ -1752,8 +1885,10 @@ public:
but just need a increased counter to track consistent view while
proceeding SELECT as part of UPDATE. */
ib_uint64_t sess_trx_id;
+
#endif /* !UNIV_HOTBACKUP */
- ibool is_encrypted;
+
+ bool is_encrypted;
#ifdef UNIV_DEBUG
/** Value of 'magic_n'. */
@@ -1764,10 +1899,13 @@ public:
#endif /* UNIV_DEBUG */
/** mysql_row_templ_t for base columns used for compute the virtual
columns */
- innodb_col_templ_t* vc_templ;
+ dict_vcol_templ_t* vc_templ;
- /** whether above vc_templ comes from purge allocation */
- bool vc_templ_purge;
+ /** encryption key, it's only for export/import */
+ byte* encryption_key;
+
+ /** encryption iv, it's only for export/import */
+ byte* encryption_iv;
};
/*******************************************************************//**
@@ -1871,29 +2009,20 @@ dict_table_autoinc_own(
}
#endif /* UNIV_DEBUG */
-/** whether a col is used in spatial index or regular index */
-enum col_spatial_status {
- /** Not used in gis index. */
- SPATIAL_NONE = 0,
-
- /** Used in both spatial index and regular index. */
- SPATIAL_MIXED = 1,
-
- /** Only used in spatial index. */
- SPATIAL_ONLY = 2
-};
-
/** Check whether the col is used in spatial index or regular index.
@param[in] col column to check
-@return col_spatial_status */
+@return spatial status */
inline
-col_spatial_status
+spatial_status_t
dict_col_get_spatial_status(
const dict_col_t* col)
{
- col_spatial_status spatial_status = SPATIAL_NONE;
+ spatial_status_t spatial_status = SPATIAL_NONE;
- ut_ad(col->ord_part);
+ /* Column is not a part of any index. */
+ if (!col->ord_part) {
+ return(spatial_status);
+ }
if (DATA_GEOMETRY_MTYPE(col->mtype)) {
if (col->max_prefix == 0) {
diff --git a/storage/innobase/include/dict0stats.h b/storage/innobase/include/dict0stats.h
index 40f254bd743..8941b399f7d 100644
--- a/storage/innobase/include/dict0stats.h
+++ b/storage/innobase/include/dict0stats.h
@@ -233,6 +233,42 @@ dict_stats_empty_defrag_stats(
dict_index_t* index); /*!< in: index to clear defragmentation stats */
+/*********************************************************************//**
+Renames an index in InnoDB persistent stats storage.
+This function creates its own transaction and commits it.
+@return DB_SUCCESS or error code. DB_STATS_DO_NOT_EXIST will be returned
+if the persistent stats do not exist. */
+dberr_t
+dict_stats_rename_index(
+/*====================*/
+ const dict_table_t* table, /*!< in: table whose index
+ is renamed */
+ const char* old_index_name, /*!< in: old index name */
+ const char* new_index_name) /*!< in: new index name */
+ MY_ATTRIBUTE((warn_unused_result));
+
+/** Save an individual index's statistic into the persistent statistics
+storage.
+@param[in] index index to be updated
+@param[in] last_update timestamp of the stat
+@param[in] stat_name name of the stat
+@param[in] stat_value value of the stat
+@param[in] sample_size n pages sampled or NULL
+@param[in] stat_description description of the stat
+@param[in,out] trx in case of NULL the function will
+allocate and free the trx object. If it is not NULL then it will be
+rolled back only in the case of error, but not freed.
+@return DB_SUCCESS or error code */
+dberr_t
+dict_stats_save_index_stat(
+ dict_index_t* index,
+ lint last_update,
+ const char* stat_name,
+ ib_uint64_t stat_value,
+ ib_uint64_t* sample_size,
+ const char* stat_description,
+ trx_t* trx);
+
#ifndef UNIV_NONINL
#include "dict0stats.ic"
#endif
diff --git a/storage/innobase/include/dict0stats_bg.h b/storage/innobase/include/dict0stats_bg.h
index e04d9ab5ab9..50c2591332e 100644
--- a/storage/innobase/include/dict0stats_bg.h
+++ b/storage/innobase/include/dict0stats_bg.h
@@ -39,6 +39,11 @@ extern os_event_t dict_stats_event;
extern mysql_pfs_key_t dict_stats_recalc_pool_mutex_key;
#endif /* HAVE_PSI_INTERFACE */
+#ifdef UNIV_DEBUG
+/** Value of MySQL global used to disable dict_stats thread. */
+extern my_bool innodb_dict_stats_disabled_debug;
+#endif /* UNIV_DEBUG */
+
/*****************************************************************//**
Add a table to the recalc pool, which is processed by the
background stats gathering thread. Only the table id is added to the
@@ -58,28 +63,6 @@ dict_stats_recalc_pool_del(
/*=======================*/
const dict_table_t* table); /*!< in: table to remove */
-/*****************************************************************//**
-Add an index in a table to the defrag pool, which is processed by the
-background stats gathering thread. Only the table id and index id are
-added to the list, so the table can be closed after being enqueued and
-it will be opened when needed. If the table or index does not exist later
-(has been DROPped), then it will be removed from the pool and skipped. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_add(
-/*=======================*/
- const dict_index_t* index); /*!< in: table to add */
-
-/*****************************************************************//**
-Delete a given index from the auto defrag pool. */
-UNIV_INTERN
-void
-dict_stats_defrag_pool_del(
-/*=======================*/
- const dict_table_t* table, /*!<in: if given, remove
- all entries for the table */
- const dict_index_t* index); /*!< in: index to remove */
-
/** Yield the data dictionary latch when waiting
for the background thread to stop accessing a table.
@param trx transaction holding the data dictionary locks */
@@ -129,6 +112,21 @@ void
dict_stats_thread_deinit();
/*======================*/
+#ifdef UNIV_DEBUG
+/** Disables dict stats thread. It's used by:
+ SET GLOBAL innodb_dict_stats_disabled_debug = 1 (0).
+@param[in] thd thread handle
+@param[in] var pointer to system variable
+@param[out] var_ptr where the formal string goes
+@param[in] save immediate result from check function */
+void
+dict_stats_disabled_debug_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save);
+#endif /* UNIV_DEBUG */
+
/*****************************************************************//**
This is the thread for background stats gathering. It pops tables, from
the auto recalc list and proceeds them, eventually recalculating their
@@ -141,6 +139,10 @@ DECLARE_THREAD(dict_stats_thread)(
void* arg); /*!< in: a dummy parameter
required by os_thread_create */
+/** Shutdown the dict stats thread. */
+void
+dict_stats_shutdown();
+
# ifndef UNIV_NONINL
# include "dict0stats_bg.ic"
# endif
diff --git a/storage/innobase/include/dict0types.h b/storage/innobase/include/dict0types.h
index 5e6e5621686..ae002dd9487 100644
--- a/storage/innobase/include/dict0types.h
+++ b/storage/innobase/include/dict0types.h
@@ -1,7 +1,7 @@
/*****************************************************************************
Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2014, SkySQL Ab. All Rights Reserved.
+Copyright (c) 2013, 2016, MariaDB Corporation. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -104,4 +104,31 @@ typedef ib_mutex_t DictSysMutex;
extern uint ibuf_debug;
#endif /* UNIV_DEBUG || UNIV_IBUF_DEBUG */
+/** Shift for spatial status */
+#define SPATIAL_STATUS_SHIFT 12
+
+/** Mask to encode/decode spatial status. */
+#define SPATIAL_STATUS_MASK (3 << SPATIAL_STATUS_SHIFT)
+
+#if SPATIAL_STATUS_MASK < REC_VERSION_56_MAX_INDEX_COL_LEN
+# error SPATIAL_STATUS_MASK < REC_VERSION_56_MAX_INDEX_COL_LEN
+#endif
+
+/** whether a col is used in spatial index or regular index
+Note: the spatial status is part of persistent undo log,
+so we should not modify the values in MySQL 5.7 */
+enum spatial_status_t {
+ /* Unkown status (undo format in 5.7.9) */
+ SPATIAL_UNKNOWN = 0,
+
+ /** Not used in gis index. */
+ SPATIAL_NONE = 1,
+
+ /** Used in both spatial index and regular index. */
+ SPATIAL_MIXED = 2,
+
+ /** Only used in spatial index. */
+ SPATIAL_ONLY = 3
+};
+
#endif
diff --git a/storage/innobase/include/dyn0buf.h b/storage/innobase/include/dyn0buf.h
index 7e2995ccabd..3126c8e4683 100644
--- a/storage/innobase/include/dyn0buf.h
+++ b/storage/innobase/include/dyn0buf.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -62,7 +62,7 @@ public:
Gets the number of used bytes in a block.
@return number of bytes used */
ulint used() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(static_cast<ulint>(m_used & ~DYN_BLOCK_FULL_FLAG));
}
@@ -71,7 +71,7 @@ public:
Gets pointer to the start of data.
@return pointer to data */
byte* start()
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_data);
}
@@ -79,7 +79,7 @@ public:
/**
@return start of data - non const version */
byte* begin()
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_data);
}
@@ -87,7 +87,7 @@ public:
/**
@return end of used data - non const version */
byte* end()
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(begin() + m_used);
}
@@ -95,7 +95,7 @@ public:
/**
@return start of data - const version */
const byte* begin() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_data);
}
@@ -103,7 +103,7 @@ public:
/**
@return end of used data - const version */
const byte* end() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(begin() + m_used);
}
@@ -216,7 +216,7 @@ public:
@param size in bytes of the buffer; MUST be <= MAX_DATA_SIZE!
@return pointer to the buffer */
byte* open(ulint size)
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(size > 0);
ut_ad(size <= MAX_DATA_SIZE);
@@ -319,7 +319,7 @@ public:
Returns the size of the total stored data.
@return data size in bytes */
ulint size() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
#ifdef UNIV_DEBUG
ulint total_size = 0;
@@ -375,7 +375,7 @@ public:
/**
@return the first block */
block_t* front()
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(UT_LIST_GET_LEN(m_list) > 0);
return(UT_LIST_GET_FIRST(m_list));
@@ -384,7 +384,7 @@ public:
/**
@return true if m_first_block block was not filled fully */
bool is_small() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_heap == NULL);
}
diff --git a/storage/innobase/include/fil0crypt.ic b/storage/innobase/include/fil0crypt.ic
index 1a91aee750e..65ca4def85f 100644
--- a/storage/innobase/include/fil0crypt.ic
+++ b/storage/innobase/include/fil0crypt.ic
@@ -17,7 +17,7 @@ this program; if not, write to the Free Software Foundation, Inc.,
*****************************************************************************/
/**************************************************//**
-@file include/fil0fil.h
+@file include/fil0crypt.ic
The low-level file system encryption support functions
Created 04/01/2015 Jan Lindström
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index d04355c3912..4171bed1611 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2016, Oracle and/or its affiliates.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2013, 2016, MariaDB Corporation.
This program is free software; you can redistribute it and/or modify it under
@@ -33,7 +33,6 @@ Created 10/25/1995 Heikki Tuuri
#include "log0recv.h"
#include "dict0types.h"
#include "page0size.h"
-#include "hash0hash.h"
#ifndef UNIV_HOTBACKUP
#include "ibuf0types.h"
#else
@@ -45,6 +44,53 @@ Created 10/25/1995 Heikki Tuuri
#include <list>
#include <vector>
+#ifdef UNIV_HOTBACKUP
+#include <cstring>
+/** determine if file is intermediate / temporary.These files are created during
+reorganize partition, rename tables, add / drop columns etc.
+@param[in] filepath asbosolute / relative or simply file name
+@retvalue true if it is intermediate file
+@retvalue false if it is normal file */
+inline
+bool
+is_intermediate_file(const std::string& filepath)
+{
+ std::string file_name = filepath;
+
+ // extract file name from relative or absolute file name
+ std::size_t pos = file_name.rfind(OS_PATH_SEPARATOR);
+ if (pos != std::string::npos)
+ file_name = file_name.substr(++pos);
+
+ transform(file_name.begin(), file_name.end(),
+ file_name.begin(), ::tolower);
+
+ if (file_name[0] != '#') {
+ pos = file_name.rfind("#tmp#.ibd");
+ if (pos != std::string::npos)
+ return true;
+ else
+ return false; /* normal file name */
+ }
+
+ std::vector<std::string> file_name_patterns = {"#sql-", "#sql2-",
+ "#tmp#", "#ren#"};
+
+ /* search for the unsupported patterns */
+ for (auto itr = file_name_patterns.begin();
+ itr != file_name_patterns.end();
+ itr++) {
+
+ if (0 == std::strncmp(file_name.c_str(),
+ itr->c_str(), itr->length())){
+ return true;
+ }
+ }
+
+ return false;
+}
+#endif /* UNIV_HOTBACKUP */
+
extern const char general_space_name[];
// Forward declaration
@@ -54,6 +100,7 @@ class truncate_t;
struct fil_node_t;
struct fil_space_t;
struct btr_create_t;
+
/* structure containing encryption specification */
typedef struct fil_space_crypt_struct fil_space_crypt_t;
@@ -92,12 +139,6 @@ struct fil_node_t;
struct fil_space_t {
char* name; /*!< Tablespace name */
ulint id; /*!< space id */
- ib_uint64_t tablespace_version;
- /*!< in DISCARD/IMPORT this timestamp
- is used to check if we should ignore
- an insert buffer merge request for a
- page because it actually was for the
- previous incarnation of the space */
lsn_t max_lsn;
/*!< LSN of the most recent
fil_names_write_if_was_clean().
@@ -181,17 +222,29 @@ struct fil_space_t {
/** Compression algorithm */
Compression::Type compression_type;
+ /** Encryption algorithm */
+ Encryption::Type encryption_type;
+
+ /** Encrypt key */
+ byte encryption_key[ENCRYPTION_KEY_LEN];
+
+ /** Encrypt key length*/
+ ulint encryption_klen;
+
+ /** Encrypt initial vector */
+ byte encryption_iv[ENCRYPTION_KEY_LEN];
+
+ /** MariaDB encryption data */
+ fil_space_crypt_t* crypt_data;
+
+ /** Space file block size */
+ ulint file_block_size;
+
+ /** True if we have already printed compression failure */
bool printed_compression_failure;
- /*!< true if we have already printed
- compression failure */
- fil_space_crypt_t* crypt_data;
- /* Tablespace crypt information or
- NULL */
- bool read_page0;
- /*!< true if page 0 of this tablespace
- is read */
- ulint file_block_size;/*!< file system block size */
+ /** True if page 0 of tablespace is read */
+ bool read_page0;
/** Release the reserved free extents.
@param[in] n_reserved number of reserved extents */
@@ -205,54 +258,53 @@ struct fil_space_t {
/** File node of a tablespace or the log data space */
struct fil_node_t {
- fil_space_t* space; /*!< backpointer to the space where this node
- belongs */
- char* name; /*!< path to the file */
- bool is_open;/*!< true if file is open */
- os_file_t handle; /*!< OS handle to the file, if file open */
- os_event_t sync_event;/*!< Condition event to group and
- serialize calls to fsync */
- bool is_raw_disk;/*!< true if the 'file' is actually a raw
- device or a raw disk partition */
- ulint size; /*!< size of the file in database pages, 0 if
- not known yet; the possible last incomplete
- megabyte may be ignored if space == 0 */
+ /** tablespace containing this file */
+ fil_space_t* space;
+ /** file name; protected by fil_system->mutex and log_sys->mutex. */
+ char* name;
+ /** whether this file is open */
+ bool is_open;
+ /** file handle (valid if is_open) */
+ os_file_t handle;
+ /** event that groups and serializes calls to fsync */
+ os_event_t sync_event;
+ /** whether the file actually is a raw device or disk partition */
+ bool is_raw_disk;
+ /** size of the file in database pages (0 if not known yet);
+ the possible last incomplete megabyte may be ignored
+ if space->id == 0 */
+ ulint size;
+ /** initial size of the file in database pages;
+ FIL_IBD_FILE_INITIAL_SIZE by default */
ulint init_size;
- /*!< initial size of the file in database pages,
- defaults to FIL_IBD_FILE_INITIAL_SIZE. */
+ /** maximum size of the file in database pages (0 if unlimited) */
ulint max_size;
- /*!< maximum size of the file in database pages;
- 0 if there is no maximum size. */
+ /** count of pending i/o's; is_open must be true if nonzero */
ulint n_pending;
- /*!< count of pending i/o's on this file;
- closing of the file is not allowed if
- this is > 0 */
+ /** count of pending flushes; is_open must be true if nonzero */
ulint n_pending_flushes;
- /*!< count of pending flushes on this file;
- closing of the file is not allowed if
- this is > 0 */
+ /** whether the file is currently being extended */
bool being_extended;
- /*!< true if the node is currently
- being extended. */
- int64_t modification_counter;/*!< when we write to the file we
- increment this by one */
- int64_t flush_counter;/*!< up to what
- modification_counter value we have
- flushed the modifications to disk */
+ /** number of writes to the file since the system was started */
+ int64_t modification_counter;
+ /** the modification_counter of the latest flush to disk */
+ int64_t flush_counter;
+ /** link to other files in this tablespace */
UT_LIST_NODE_T(fil_node_t) chain;
- /*!< link field for the file chain */
+ /** link to the fil_system->LRU list (keeping track of open files) */
UT_LIST_NODE_T(fil_node_t) LRU;
- /*!< link field for the LRU list */
- ulint magic_n;/*!< FIL_NODE_MAGIC_N */
- /** true if the FS where the file is located supports PUNCH HOLE */
+ /** whether the file system of this file supports PUNCH HOLE */
bool punch_hole;
- /** Block size to use for punching holes */
- ulint block_size;
+ /** block size to use for punching holes */
+ ulint block_size;
- /** True if atomic write is enabled for this file */
+ /** whether atomic write is enabled for this file */
bool atomic_write;
+
+ /** FIL_NODE_MAGIC_N */
+ ulint magic_n;
};
/** Value of fil_node_t::magic_n */
@@ -263,12 +315,14 @@ enum ib_extention {
NO_EXT = 0,
IBD = 1,
ISL = 2,
- CFG = 3
+ CFG = 3,
+ CFP = 4
};
extern const char* dot_ext[];
#define DOT_IBD dot_ext[IBD]
#define DOT_ISL dot_ext[ISL]
#define DOT_CFG dot_ext[CFG]
+#define DOT_CPF dot_ext[CFP]
/** Wrapper for a path to a directory.
This folder may or may not yet esist. Since not all directory paths
@@ -473,6 +527,7 @@ static const ulint FIL_PAGE_COMPRESS_SIZE_V1 = FIL_PAGE_ORIGINAL_SIZE_V1 + 2;
#define FIL_PAGE_SPACE_ID FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID
#define FIL_PAGE_DATA 38U /*!< start of the data on the page */
+
/* Following are used when page compression is used */
#define FIL_PAGE_COMPRESSED_SIZE 2 /*!< Number of bytes used to store
actual payload data size on
@@ -512,6 +567,10 @@ static const ulint FIL_PAGE_COMPRESS_SIZE_V1 = FIL_PAGE_ORIGINAL_SIZE_V1 + 2;
in FIL_PAGE_TYPE is replaced with this
value when flushing pages. */
#define FIL_PAGE_COMPRESSED 14 /*!< Compressed page */
+#define FIL_PAGE_ENCRYPTED 15 /*!< Encrypted page */
+#define FIL_PAGE_COMPRESSED_AND_ENCRYPTED 16
+ /*!< Compressed and Encrypted page */
+#define FIL_PAGE_ENCRYPTED_RTREE 17 /*!< Encrypted R-tree page */
/** Used by i_s.cc to index into the text description. */
#define FIL_PAGE_TYPE_LAST FIL_PAGE_TYPE_UNKNOWN
@@ -540,6 +599,20 @@ extern ulint fil_n_pending_tablespace_flushes;
/** Number of files currently open */
extern ulint fil_n_file_opened;
+/** Look up a tablespace.
+The caller should hold an InnoDB table lock or a MDL that prevents
+the tablespace from being dropped during the operation,
+or the caller should be in single-threaded crash recovery mode
+(no user connections that could drop tablespaces).
+If this is not the case, fil_space_acquire() and fil_space_release()
+should be used instead.
+@param[in] id tablespace ID
+@return tablespace, or NULL if not found */
+fil_space_t*
+fil_space_get(
+ ulint id)
+ MY_ATTRIBUTE((warn_unused_result));
+
/** The tablespace memory cache; also the totality of logs (the log
data space) is stored here; below we talk about tablespaces, but also
the ib_logfiles form a 'space' and it is handled here */
@@ -602,30 +675,13 @@ struct fil_system_t {
potential space_id reuse */
};
-#ifndef UNIV_HOTBACKUP
-/** Look up a tablespace.
-The caller should hold an InnoDB table lock or a MDL that prevents
-the tablespace from being dropped during the operation,
-or the caller should be in single-threaded crash recovery mode
-(no user connections that could drop tablespaces).
-If this is not the case, fil_space_acquire() and fil_space_release()
-should be used instead.
-@param[in] id tablespace ID
-@return tablespace, or NULL if not found */
-fil_space_t*
-fil_space_get(
- ulint id)
- __attribute__((warn_unused_result));
+/** The tablespace memory cache. This variable is NULL before the module is
+initialized. */
+extern fil_system_t* fil_system;
-/*******************************************************************//**
-Returns the version number of a tablespace, -1 if not found.
-@return version number, -1 if the tablespace does not exist in the
-memory cache */
-UNIV_INTERN
-ib_uint64_t
-fil_space_get_version(
-/*==================*/
- ulint id); /*!< in: space id */
+#include "fil0crypt.h"
+
+#ifndef UNIV_HOTBACKUP
/** Returns the latch of a file space.
@param[in] id space id
@param[out] flags tablespace flags
@@ -658,7 +714,7 @@ fil_space_set_imported(
@return whether it is a temporary tablespace */
bool
fsp_is_temporary(ulint id)
-__attribute__((warn_unused_result, pure));
+MY_ATTRIBUTE((warn_unused_result, pure));
# endif /* UNIV_DEBUG */
#endif /* !UNIV_HOTBACKUP */
@@ -680,7 +736,7 @@ fil_node_create(
bool is_raw,
bool atomic_write,
ulint max_pages = ULINT_MAX)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Create a space memory object and put it to the fil_system hash table.
The tablespace name is independent from the tablespace file-name.
@@ -693,12 +749,12 @@ Error messages are issued to the server log.
@retval NULL on failure (such as when the same tablespace exists) */
fil_space_t*
fil_space_create(
- const char* name, /*!< in: space name */
- ulint id, /*!< in: space id */
+ const char* name,
+ ulint id,
ulint flags,
fil_type_t purpose, /*!< in: FIL_TABLESPACE, or FIL_LOG if log */
fil_space_crypt_t* crypt_data) /*!< in: crypt data */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Assigns a new space id for a new single-table tablespace. This works simply by
@@ -820,22 +876,15 @@ fil_set_max_space_id_if_bigger(
/*===========================*/
ulint max_id);/*!< in: maximum known id */
#ifndef UNIV_HOTBACKUP
-/*******************************************************************//**
-Increments the count of pending operation, if space is not being deleted.
-@return TRUE if being deleted, and operation should be skipped */
-UNIV_INTERN
-ibool
-fil_inc_pending_ops(
-/*================*/
- ulint id, /*!< in: space id */
- ibool print_err); /*!< in: need to print error or not */
-/*******************************************************************//**
-Decrements the count of pending operations. */
-UNIV_INTERN
-void
-fil_decr_pending_ops(
-/*=================*/
- ulint id); /*!< in: space id */
+
+/** Write the flushed LSN to the page header of the first page in the
+system tablespace.
+@param[in] lsn flushed LSN
+@return DB_SUCCESS or error number */
+dberr_t
+fil_write_flushed_lsn(
+ lsn_t lsn)
+MY_ATTRIBUTE((warn_unused_result));
/** Acquire a tablespace when it could be dropped concurrently.
Used by background threads that do not necessarily hold proper locks
@@ -845,7 +894,7 @@ for concurrency control.
fil_space_t*
fil_space_acquire(
ulint id)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Acquire a tablespace that may not exist.
Used by background threads that do not necessarily hold proper locks
@@ -855,7 +904,7 @@ for concurrency control.
fil_space_t*
fil_space_acquire_silent(
ulint id)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Release a tablespace acquired with fil_space_acquire().
@param[in,out] space tablespace to release */
@@ -919,6 +968,7 @@ private:
};
#endif /* !UNIV_HOTBACKUP */
+
/********************************************************//**
Creates the database directory for a table if it does not exist yet. */
void
@@ -968,7 +1018,7 @@ fil_op_replay_rename(
ulint first_page_no,
const char* name,
const char* new_name)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Deletes an IBD tablespace, either general or single-table.
The tablespace must be cached in the memory cache. This will delete the
@@ -1084,8 +1134,6 @@ fil_make_filepath(
ib_extention suffix,
bool strip_name);
-#include "fil0crypt.h"
-
/** Creates a new General or Single-Table tablespace
@param[in] space_id Tablespace ID
@param[in] name Tablespace name in dbname/tablename format.
@@ -1104,9 +1152,8 @@ fil_ibd_create(
ulint size,
fil_encryption_t mode, /*!< in: encryption mode */
ulint key_id) /*!< in: encryption key_id */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
-#ifndef UNIV_HOTBACKUP
/********************************************************************//**
Tries to open a single-table tablespace and optionally checks the space id is
right in it. If does not succeed, prints an error message to the .err log. This
@@ -1146,7 +1193,7 @@ fil_ibd_open(
const char* tablename,
const char* path_in,
dict_table_t* table) /*!< in: table */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
enum fil_load_status {
/** The tablespace file(s) were found and valid. */
@@ -1169,9 +1216,8 @@ fil_ibd_load(
ulint space_id,
const char* filename,
fil_space_t*& space)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
-#endif /* !UNIV_HOTBACKUP */
/***********************************************************************//**
A fault-tolerant function that tries to read the next file name in the
@@ -1268,6 +1314,11 @@ fil_space_get_n_reserved_extents(
aligned
@param[in] message message for aio handler if non-sync aio
used, else ignored
+@param[in,out] write_size Actual write size initialized
+ after fist successfull trim
+ operation for this page and if
+ nitialized we do not trim again if
+ Actual page
@return DB_SUCCESS, DB_TABLESPACE_DELETED or DB_TABLESPACE_TRUNCATED
if we are trying to do i/o on a tablespace which does not exist */
@@ -1281,11 +1332,7 @@ fil_io(
ulint len,
void* buf,
void* message,
- ulint* write_size); /*!< in/out: Actual write size initialized
- after fist successfull trim
- operation for this page and if
- initialized we do not trim again if
- actual page size does not decrease. */
+ ulint* write_size);
/**********************************************************************//**
Waits for an aio operation to complete. This function is used to write the
handler for completed requests. The aio array of pending requests is divided
@@ -1477,6 +1524,10 @@ struct PageCallback {
@return the space id of the tablespace */
virtual ulint get_space_id() const UNIV_NOTHROW = 0;
+ /**
+ @retval the space flags of the tablespace being iterated over */
+ virtual ulint get_space_flags() const UNIV_NOTHROW = 0;
+
/** Set the tablespace table size.
@param[in] page a page belonging to the tablespace */
void set_page_size(const buf_frame_t* page) UNIV_NOTHROW;
@@ -1515,7 +1566,7 @@ fil_tablespace_iterate(
dict_table_t* table,
ulint n_io_buffers,
PageCallback& callback)
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Looks for a pre-existing fil_space_t with the given tablespace ID
@@ -1575,16 +1626,71 @@ fil_node_next(
@param[in] new_table new table
@param[in] tmp_name temporary table name
@param[in,out] mtr mini-transaction
-@return whether the operation succeeded */
-bool
+@return innodb error code */
+dberr_t
fil_mtr_rename_log(
const dict_table_t* old_table,
const dict_table_t* new_table,
const char* tmp_name,
mtr_t* mtr)
- MY_ATTRIBUTE((nonnull));
+ MY_ATTRIBUTE((warn_unused_result));
+
+/****************************************************************//**
+Acquire fil_system mutex */
+void
+fil_system_enter(void);
+/*==================*/
+/****************************************************************//**
+Release fil_system mutex */
+void
+fil_system_exit(void);
+/*==================*/
+
+/*******************************************************************//**
+Returns the table space by a given id, NULL if not found. */
+fil_space_t*
+fil_space_found_by_id(
+/*==================*/
+ ulint id); /*!< in: space id */
+
+/*******************************************************************//**
+Returns the table space by a given id, NULL if not found. */
+fil_space_t*
+fil_space_get_by_id(
+/*================*/
+ ulint id); /*!< in: space id */
+
+/******************************************************************
+Get id of first tablespace or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_first_space();
+/*=================*/
-/** Note that a non-predefined persistent tablespace has been modified
+/******************************************************************
+Get id of next tablespace or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_next_space(
+ ulint id); /*!< in: space id */
+
+/******************************************************************
+Get id of first tablespace that has node or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_first_space_safe();
+/*======================*/
+
+/******************************************************************
+Get id of next tablespace that has node or ULINT_UNDEFINED if none */
+UNIV_INTERN
+ulint
+fil_get_next_space_safe(
+/*====================*/
+ ulint id); /*!< in: previous space id */
+
+
+/*******************************************************************//**
by redo log.
@param[in,out] space tablespace */
void
@@ -1601,30 +1707,49 @@ fil_names_dirty_and_write(
fil_space_t* space,
mtr_t* mtr);
-/** Set the compression type for the tablespace
-@param[in] space Space ID of tablespace for which to set
-@param[in] algorithm Text representation of the algorithm
+/** Set the compression type for the tablespace of a table
+@param[in] table Table that should be compressesed
+@param[in] algorithm Text representation of the algorithm
@return DB_SUCCESS or error code */
dberr_t
fil_set_compression(
- ulint space_id,
+ dict_table_t* table,
const char* algorithm)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
-/**
-@param[in] space_id Space ID to check
+/** Get the compression type for the tablespace
+@param[in] space_id Space ID to check
@return the compression algorithm */
Compression::Type
fil_get_compression(
- ulint space_id)
- __attribute__((warn_unused_result));
+ ulint space_id)
+ MY_ATTRIBUTE((warn_unused_result));
+
+/** Set the encryption type for the tablespace
+@param[in] space Space ID of tablespace for which to set
+@param[in] algorithm Encryption algorithm
+@param[in] key Encryption key
+@param[in] iv Encryption iv
+@return DB_SUCCESS or error code */
+dberr_t
+fil_set_encryption(
+ ulint space_id,
+ Encryption::Type algorithm,
+ byte* key,
+ byte* iv)
+ MY_ATTRIBUTE((warn_unused_result));
+
+/**
+@return true if the re-encrypt success */
+bool
+fil_encryption_rotate();
/** Write MLOG_FILE_NAME records if a persistent tablespace was modified
for the first time since the latest fil_names_clear().
@param[in,out] space tablespace
@param[in,out] mtr mini-transaction
@return whether any MLOG_FILE_NAME record was written */
-inline __attribute__((warn_unused_result))
+inline MY_ATTRIBUTE((warn_unused_result))
bool
fil_names_write_if_was_clean(
fil_space_t* space,
@@ -1701,72 +1826,6 @@ void fil_no_punch_hole(fil_node_t* node);
void test_make_filepath();
#endif /* UNIV_ENABLE_UNIT_TEST_MAKE_FILEPATH */
-/*******************************************************************//**
-Return space flags */
-UNIV_INLINE
-ulint
-fil_space_flags(
-/*===========*/
- fil_space_t* space); /*!< in: space */
-
-#endif /* !UNIV_INNOCHECKSUM */
-
-/****************************************************************//**
-Acquire fil_system mutex */
-void
-fil_system_enter(void);
-/*==================*/
-/****************************************************************//**
-Release fil_system mutex */
-void
-fil_system_exit(void);
-/*==================*/
-
-#ifndef UNIV_INNOCHECKSUM
-/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
-fil_space_t*
-fil_space_found_by_id(
-/*==================*/
- ulint id); /*!< in: space id */
-
-/*******************************************************************//**
-Returns the table space by a given id, NULL if not found. */
-fil_space_t*
-fil_space_get_by_id(
-/*================*/
- ulint id); /*!< in: space id */
-
-/******************************************************************
-Get id of first tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_first_space();
-/*=================*/
-
-/******************************************************************
-Get id of next tablespace or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_next_space(
-/*===============*/
- ulint id); /*!< in: space id */
-
-/******************************************************************
-Get id of first tablespace that has node or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_first_space_safe();
-/*======================*/
-
-/******************************************************************
-Get id of next tablespace that has node or ULINT_UNDEFINED if none */
-UNIV_INTERN
-ulint
-fil_get_next_space_safe(
-/*====================*/
- ulint id); /*!< in: previous space id */
-
/*******************************************************************//**
Returns the block size of the file space
@@ -1779,15 +1838,24 @@ fil_space_get_block_size(
ulint offset, /*!< in: page offset */
ulint len); /*!< in: page len */
-#endif /* UNIV_INNOCHECKSUM */
+/*******************************************************************//**
+Increments the count of pending operation, if space is not being deleted.
+@return TRUE if being deleted, and operation should be skipped */
+UNIV_INTERN
+ibool
+fil_inc_pending_ops(
+/*================*/
+ ulint id, /*!< in: space id */
+ ibool print_err); /*!< in: need to print error or not */
+/*******************************************************************//**
+Decrements the count of pending operations. */
+UNIV_INTERN
+void
+fil_decr_pending_ops(
+/*=================*/
+ ulint id); /*!< in: space id */
-/** Write the flushed LSN to the page header of the first page in the
-system tablespace.
-@param[in] lsn flushed LSN
-@return DB_SUCCESS or error number */
-dberr_t
-fil_write_flushed_lsn(
- lsn_t lsn);
+#endif /* UNIV_INNOCHECKSUM */
#ifndef UNIV_INNOCHECKSUM
#ifndef UNIV_NONINL
diff --git a/storage/innobase/include/fsp0file.h b/storage/innobase/include/fsp0file.h
index a08ebff9509..83aa370abf0 100644
--- a/storage/innobase/include/fsp0file.h
+++ b/storage/innobase/include/fsp0file.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -68,6 +68,8 @@ public:
m_atomic_write(),
m_last_os_error(),
m_file_info(),
+ m_encryption_key(NULL),
+ m_encryption_iv(NULL),
m_crypt_info()
{
/* No op */
@@ -92,6 +94,8 @@ public:
m_atomic_write(),
m_last_os_error(),
m_file_info(),
+ m_encryption_key(NULL),
+ m_encryption_iv(NULL),
m_crypt_info()
{
ut_ad(m_name != NULL);
@@ -114,6 +118,8 @@ public:
m_atomic_write(file.m_atomic_write),
m_last_os_error(),
m_file_info(),
+ m_encryption_key(NULL),
+ m_encryption_iv(NULL),
m_crypt_info()
{
m_name = mem_strdup(file.m_name);
@@ -172,6 +178,8 @@ public:
it should be reread if needed */
m_first_page_buf = NULL;
m_first_page = NULL;
+ m_encryption_key = NULL;
+ m_encryption_iv = NULL;
/* Do not copy crypt info it is read from first page */
m_crypt_info = NULL;
@@ -200,7 +208,7 @@ public:
are enforced.
@return DB_SUCCESS or error code */
virtual dberr_t open_read_write(bool read_only_mode)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Initialize OS specific file info. */
void init_file_info();
@@ -237,12 +245,14 @@ public:
successfully opened in order for this function to validate it.
@param[in] space_id The expected tablespace ID.
@param[in] flags The expected tablespace flags.
+ @param[in] for_import is it for importing
@retval DB_SUCCESS if tablespace is valid, DB_ERROR if not.
m_is_valid is also set true on success, else false. */
dberr_t validate_to_dd(
- ulint space_id,
- ulint flags)
- __attribute__((warn_unused_result));
+ ulint space_id,
+ ulint flags,
+ bool for_import)
+ MY_ATTRIBUTE((warn_unused_result));
/** Validates this datafile for the purpose of recovery.
The file should exist and be successfully opened. We initially
@@ -253,19 +263,21 @@ public:
@retval DB_SUCCESS if tablespace is valid, DB_ERROR if not.
m_is_valid is also set true on success, else false. */
dberr_t validate_for_recovery()
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Checks the consistency of the first page of a datafile when the
tablespace is opened. This occurs before the fil_space_t is created
so the Space ID found here must not already be open.
m_is_valid is set true on success, else false.
@param[out] flush_lsn contents of FIL_PAGE_FILE_FLUSH_LSN
+ @param[in] for_import if it is for importing
(only valid for the first file of the system tablespace)
@retval DB_SUCCESS on if the datafile is valid
@retval DB_CORRUPTION if the datafile is not readable
@retval DB_TABLESPACE_EXISTS if there is a duplicate space_id */
- dberr_t validate_first_page(lsn_t* flush_lsn = 0)
- __attribute__((warn_unused_result));
+ dberr_t validate_first_page(lsn_t* flush_lsn,
+ bool for_import)
+ MY_ATTRIBUTE((warn_unused_result));
/** Get Datafile::m_name.
@return m_name */
@@ -370,7 +382,7 @@ private:
are enforced.
@return DB_SUCCESS or error code */
dberr_t open_or_create(bool read_only_mode)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Reads a few significant fields from the first page of the
datafile, which must already be open.
@@ -378,7 +390,7 @@ private:
are enforced.
@return DB_SUCCESS or DB_IO_ERROR if page cannot be read */
dberr_t read_first_page(bool read_first_page)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Free the first page from memory when it is no longer needed. */
void free_first_page();
@@ -480,8 +492,14 @@ public:
struct stat m_file_info;
#endif /* WIN32 */
+ /** Encryption key read from first page */
+ byte* m_encryption_key;
+
+ /** Encryption iv read from first page */
+ byte* m_encryption_iv;
+
/** Encryption information */
- fil_space_crypt_t* m_crypt_info;
+ fil_space_crypt_t* m_crypt_info;
};
@@ -551,7 +569,7 @@ public:
are enforced.
@return DB_SUCCESS or error code */
dberr_t open_read_write(bool read_only_mode)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************
Global Static Functions; Cannot refer to data members.
diff --git a/storage/innobase/include/fsp0fsp.h b/storage/innobase/include/fsp0fsp.h
index 17be27a8ce5..3709c4a4f24 100644
--- a/storage/innobase/include/fsp0fsp.h
+++ b/storage/innobase/include/fsp0fsp.h
@@ -42,6 +42,7 @@ Created 12/18/1995 Heikki Tuuri
#endif /* !UNIV_INNOCHECKSUM */
#include "fsp0types.h"
+
#define FSP_FLAGS_POS_DATA_DIR_ORACLE (FSP_FLAGS_POS_ATOMIC_BLOBS \
+ FSP_FLAGS_WIDTH_ATOMIC_BLOBS \
+ FSP_FLAGS_WIDTH_PAGE_SSIZE)
@@ -49,6 +50,7 @@ Created 12/18/1995 Heikki Tuuri
#define FSP_FLAGS_MASK_DATA_DIR_ORACLE \
((~(~0 << FSP_FLAGS_WIDTH_DATA_DIR)) \
<< FSP_FLAGS_POS_DATA_DIR_ORACLE)
+
#define FSP_FLAGS_HAS_DATA_DIR_ORACLE(flags) \
((flags & FSP_FLAGS_MASK_DATA_DIR_ORACLE) \
>> FSP_FLAGS_POS_DATA_DIR_ORACLE)
@@ -118,6 +120,7 @@ descriptor page, but used only in the first. */
FSP_FREE_LIMIT at a time */
/* @} */
+#ifndef UNIV_INNOCHECKSUM
/* @defgroup File Segment Inode Constants (moved from fsp0fsp.c) @{ */
@@ -254,7 +257,6 @@ the extent are free and which contain old tuple version to clean. */
/* @} */
-#ifndef UNIV_INNOCHECKSUM
/**********************************************************************//**
Initializes the file space system. */
void
@@ -334,6 +336,40 @@ page_size_t
fsp_header_get_page_size(
const page_t* page);
+/** Decoding the encryption info
+from the first page of a tablespace.
+@param[in/out] key key
+@param[in/out] iv iv
+@param[in] encryption_info encrytion info.
+@return true if success */
+bool
+fsp_header_decode_encryption_info(
+ byte* key,
+ byte* iv,
+ byte* encryption_info);
+
+/** Reads the encryption key from the first page of a tablespace.
+@param[in] fsp_flags tablespace flags
+@param[in/out] key tablespace key
+@param[in/out] iv tablespace iv
+@param[in] page first page of a tablespace
+@return true if success */
+bool
+fsp_header_get_encryption_key(
+ ulint fsp_flags,
+ byte* key,
+ byte* iv,
+ page_t* page);
+
+/** Check the encryption key from the first page of a tablespace.
+@param[in] fsp_flags tablespace flags
+@param[in] page first page of a tablespace
+@return true if success */
+bool
+fsp_header_check_encryption_key(
+ ulint fsp_flags,
+ page_t* page);
+
/**********************************************************************//**
Writes the space id and flags to a tablespace header. The flags contain
row type, physical/compressed page size, and logical/uncompressed page
@@ -346,6 +382,17 @@ fsp_header_init_fields(
ulint flags); /*!< in: tablespace flags (FSP_SPACE_FLAGS):
0, or table->flags if newer than COMPACT */
+/** Rotate the encryption info in the space header.
+@param[in] space tablespace
+@param[in] encrypt_info buffer for re-encrypt key.
+@param[in,out] mtr mini-transaction
+@return true if success. */
+bool
+fsp_header_rotate_encryption(
+ fil_space_t* space,
+ byte* encrypt_info,
+ mtr_t* mtr);
+
/** Initializes the space header of a new created space and creates also the
insert buffer tree root if space == 0.
@param[in] space_id space id
@@ -458,8 +505,8 @@ fseg_alloc_free_page_general(
If init_mtr!=mtr, but the page is already
latched in mtr, do not initialize the page. */
MY_ATTRIBUTE((warn_unused_result, nonnull));
-/**********************************************************************//**
-Reserves free pages from a tablespace. All mini-transactions which may
+
+/** Reserves free pages from a tablespace. All mini-transactions which may
use several pages from the tablespace should call this function beforehand
and reserve enough free extents so that they certainly will be able
to do their operation, like a B-tree page split, fully. Reservations
@@ -478,23 +525,33 @@ The purpose is to avoid dead end where the database is full but the
user cannot free any space because these freeing operations temporarily
reserve some space.
-Single-table tablespaces whose size is < 32 pages are a special case. In this
-function we would liberally reserve several 64 page extents for every page
-split or merge in a B-tree. But we do not want to waste disk space if the table
-only occupies < 32 pages. That is why we apply different rules in that special
-case, just ensuring that there are 3 free pages available.
-@return TRUE if we were able to make the reservation */
+Single-table tablespaces whose size is < FSP_EXTENT_SIZE pages are a special
+case. In this function we would liberally reserve several extents for
+every page split or merge in a B-tree. But we do not want to waste disk space
+if the table only occupies < FSP_EXTENT_SIZE pages. That is why we apply
+different rules in that special case, just ensuring that there are n_pages
+free pages available.
+
+@param[out] n_reserved number of extents actually reserved; if we
+ return true and the tablespace size is <
+ FSP_EXTENT_SIZE pages, then this can be 0,
+ otherwise it is n_ext
+@param[in] space_id tablespace identifier
+@param[in] n_ext number of extents to reserve
+@param[in] alloc_type page reservation type (FSP_BLOB, etc)
+@param[in,out] mtr the mini transaction
+@param[in] n_pages for small tablespaces (tablespace size is
+ less than FSP_EXTENT_SIZE), number of free
+ pages to reserve.
+@return true if we were able to make the reservation */
bool
fsp_reserve_free_extents(
-/*=====================*/
- ulint* n_reserved,/*!< out: number of extents actually reserved; if we
- return TRUE and the tablespace size is < 64 pages,
- then this can be 0, otherwise it is n_ext */
- ulint space_id,/*!< in: space id */
- ulint n_ext, /*!< in: number of extents to reserve */
+ ulint* n_reserved,
+ ulint space_id,
+ ulint n_ext,
fsp_reserve_t alloc_type,
- /*!< in: page reservation type */
- mtr_t* mtr); /*!< in/out: mini-transaction */
+ mtr_t* mtr,
+ ulint n_pages = 2);
/** Calculate how many KiB of new data we will be able to insert to the
tablespace without running out of space.
@@ -551,7 +608,7 @@ fseg_free_step(
bool ahi, /*!< in: whether we may need to drop
the adaptive hash index */
mtr_t* mtr) /*!< in/out: mini-transaction */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Frees part of a segment. Differs from fseg_free_step because this function
leaves the header page unfreed.
@@ -564,7 +621,7 @@ fseg_free_step_not_header(
bool ahi, /*!< in: whether we may need to drop
the adaptive hash index */
mtr_t* mtr) /*!< in/out: mini-transaction */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Checks if a page address is an extent descriptor page address.
@param[in] page_id page id
@@ -629,6 +686,7 @@ fsp_flags_are_equal(
@param[in] has_data_dir This tablespace is in a remote location.
@param[in] is_shared This tablespace can be shared by many tables.
@param[in] is_temporary This tablespace is temporary.
+@param[in] is_encrypted This tablespace is encrypted.
@return tablespace flags after initialization */
UNIV_INLINE
ulint
@@ -640,7 +698,8 @@ fsp_flags_init(
bool is_temporary,
bool page_compression,
ulint page_compression_level,
- ulint atomic_writes);
+ ulint atomic_writes,
+ bool is_encrypted = false);
/** Convert a 32 bit integer tablespace flags to the 32 bit table flags.
This can only be done for a tablespace that was built as a file-per-table
@@ -687,7 +746,7 @@ xdes_get_descriptor(
ulint offset,
const page_size_t& page_size,
mtr_t* mtr)
-__attribute__((warn_unused_result));
+MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Gets a descriptor bit of a page.
@@ -710,11 +769,11 @@ ulint
xdes_calc_descriptor_page(
const page_size_t& page_size,
ulint offset);
-#endif /* !UNIV_INNOCHECKSUM */
+#endif /* !UNIV_INNOCHECKSUM */
-/*********************************************************************/
-/* @return offset into fsp header where crypt data is stored */
+/*********************************************************************//**
+@return offset into fsp header where crypt data is stored */
UNIV_INTERN
ulint
fsp_header_get_crypt_offset(
@@ -722,10 +781,9 @@ fsp_header_get_crypt_offset(
const page_size_t& page_size,/*!< in: page size */
ulint* max_size); /*!< out: free space after offset */
-#define fsp_page_is_free(space,page,mtr) \
- fsp_page_is_free_func(space,page,mtr, __FILE__, __LINE__)
#ifndef UNIV_INNOCHECKSUM
+
/**********************************************************************//**
Checks if a single page is free.
@return true if free */
@@ -738,7 +796,12 @@ fsp_page_is_free_func(
mtr_t* mtr, /*!< in/out: mini-transaction */
const char *file,
ulint line);
-#endif
+
+#define fsp_page_is_free(space,page,mtr) \
+ fsp_page_is_free_func(space,page,mtr, __FILE__, __LINE__)
+
+#endif /* UNIV_INNOCHECKSUM */
+
#ifndef UNIV_NONINL
#include "fsp0fsp.ic"
#endif
diff --git a/storage/innobase/include/fsp0fsp.ic b/storage/innobase/include/fsp0fsp.ic
index e204ac3c69f..475dd238728 100644
--- a/storage/innobase/include/fsp0fsp.ic
+++ b/storage/innobase/include/fsp0fsp.ic
@@ -1,7 +1,7 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, SkySQL Ab. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, MariaDB Corporation.
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
@@ -181,10 +181,11 @@ fsp_flags_set_page_size(
@param[in] has_data_dir This tablespace is in a remote location.
@param[in] is_shared This tablespace can be shared by many tables.
@param[in] is_temporary This tablespace is temporary.
+@param[in] is_encrypted This tablespace is encrypted.
@param[in] page_compressed Table uses page compression
@param[in] page_compression_level Page compression level
@param[in] atomic_writes Table uses atomic writes
-@return tablespace flags after initialization */
+@@return tablespace flags after initialization */
UNIV_INLINE
ulint
fsp_flags_init(
@@ -195,7 +196,8 @@ fsp_flags_init(
bool is_temporary,
bool page_compression,
ulint page_compression_level,
- ulint atomic_writes)
+ ulint atomic_writes,
+ bool is_encrypted)
{
ut_ad(page_size.physical() <= page_size.logical());
ut_ad(!page_size.is_compressed() || atomic_blobs);
@@ -229,6 +231,10 @@ fsp_flags_init(
flags |= FSP_FLAGS_MASK_TEMPORARY;
}
+ if (is_encrypted) {
+ flags |= FSP_FLAGS_MASK_ENCRYPTION;
+ }
+
/* In addition, tablespace flags also contain if the page
compression is used for this table. */
if (page_compression) {
@@ -247,6 +253,8 @@ fsp_flags_init(
flags |= FSP_FLAGS_SET_ATOMIC_WRITES(flags, atomic_writes);
}
+ ut_ad(fsp_flags_is_valid(flags));
+
return(flags);
}
@@ -329,4 +337,15 @@ xdes_calc_descriptor_page(
return(ut_2pow_round(offset, page_size.physical()));
}
+
+/** Calculates the descriptor array size.
+@param[in] page_size page size
+@return size of descriptor array */
+UNIV_INLINE
+ulint
+xdes_arr_size(
+ const page_size_t& page_size)
+{
+ return(page_size.physical()/FSP_EXTENT_SIZE);
+}
#endif /* !UNIV_INNOCHECKSUM */
diff --git a/storage/innobase/include/fsp0space.h b/storage/innobase/include/fsp0space.h
index 5fdb12a922f..603c71b4aa6 100644
--- a/storage/innobase/include/fsp0space.h
+++ b/storage/innobase/include/fsp0space.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -100,7 +100,7 @@ public:
m_path = mem_strdupl(path, len);
ut_ad(m_path != NULL);
- os_normalize_path_for_win(m_path);
+ os_normalize_path(m_path);
}
/** Set tablespace path and filename members.
@@ -171,15 +171,24 @@ public:
/** Free the memory allocated by the Tablespace object */
void shutdown();
- /**
- @return ULINT_UNDEFINED if the size is invalid else the sum of sizes */
- ulint get_sum_of_sizes() const;
+ /** @return the sum of the file sizes of each Datafile */
+ ulint get_sum_of_sizes() const
+ {
+ ulint sum = 0;
+
+ for (files_t::const_iterator it = m_files.begin();
+ it != m_files.end(); ++it) {
+ sum += it->m_size;
+ }
+
+ return(sum);
+ }
/** Open or Create the data files if they do not exist.
@param[in] is_temp whether this is a temporary tablespace
@return DB_SUCCESS or error code */
dberr_t open_or_create(bool is_temp)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Delete all the data files. */
void delete_files();
diff --git a/storage/innobase/include/fsp0sysspace.h b/storage/innobase/include/fsp0sysspace.h
index 42778f7d8e6..226d53ebd50 100644
--- a/storage/innobase/include/fsp0sysspace.h
+++ b/storage/innobase/include/fsp0sysspace.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -152,6 +152,15 @@ public:
* ((1024 * 1024) / UNIV_PAGE_SIZE));
}
+ /** Roundoff to MegaBytes is similar as done in
+ SysTablespace::parse_units() function.
+ @return the pages when given size of file (bytes). */
+ ulint get_pages_from_size(os_offset_t size)
+ {
+ return (ulint)((size / (1024 * 1024))
+ * ((1024 * 1024) / UNIV_PAGE_SIZE));
+ }
+
/**
@return next increment size */
ulint get_increment() const;
@@ -167,7 +176,7 @@ public:
bool create_new_db,
ulint* sum_new_sizes,
lsn_t* flush_lsn)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
private:
/** Check the tablespace header for this tablespace.
@@ -289,17 +298,6 @@ is_system_tablespace(
|| id == srv_tmp_space.space_id());
}
-/** Check if it is a shared tablespace.
-@param[in] id Space ID to check
-@return true if id is a shared tablespace, false if not. */
-UNIV_INLINE
-bool
-is_shared_tablespace(
- ulint id)
-{
- return(is_system_tablespace(id));
-}
-
/** Check if shared-system or undo tablespace.
@return true if shared-system or undo tablespace */
UNIV_INLINE
diff --git a/storage/innobase/include/fsp0types.h b/storage/innobase/include/fsp0types.h
index 33f630a3574..73fd6341d94 100644
--- a/storage/innobase/include/fsp0types.h
+++ b/storage/innobase/include/fsp0types.h
@@ -1,6 +1,7 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, MariaDB Corporation.
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
@@ -62,7 +63,7 @@ page size | file space extent size
#define FSP_EXTENT_SIZE_MAX (4194304 / UNIV_PAGE_SIZE_MAX)
/** File space extent size (one megabyte) in pages for MIN page size */
-#define FSP_EXTENT_SIZE_MIN (1048576U / UNIV_PAGE_SIZE_MIN)
+#define FSP_EXTENT_SIZE_MIN (1048576 / UNIV_PAGE_SIZE_MIN)
/** On a page of any file segment, data may be put starting from this
offset */
@@ -190,7 +191,7 @@ so they should have a file format number plus the DICT_TF_COMPACT bit set.
bool
fsp_flags_is_valid(
ulint flags)
- __attribute__((warn_unused_result, const));
+ MY_ATTRIBUTE((warn_unused_result, const));
/** Check if tablespace is system temporary.
@param[in] space_id verify is checksum is enabled for given space.
@@ -249,6 +250,9 @@ was created with CREATE TABLESPACE and can be shared by multiple tables. */
is a temporary tablespace and everything in it is temporary, meaning that
it is for a single client and should be deleted upon startup if it exists. */
#define FSP_FLAGS_WIDTH_TEMPORARY 1
+/** Width of the encryption flag. This flag indicates that the tablespace
+is a tablespace with encryption. */
+#define FSP_FLAGS_WIDTH_ENCRYPTION 1
/** Number of flag bits used to indicate the page compression and compression level */
#define FSP_FLAGS_WIDTH_PAGE_COMPRESSION 1
@@ -265,6 +269,7 @@ it is for a single client and should be deleted upon startup if it exists. */
+ FSP_FLAGS_WIDTH_DATA_DIR \
+ FSP_FLAGS_WIDTH_SHARED \
+ FSP_FLAGS_WIDTH_TEMPORARY \
+ + FSP_FLAGS_WIDTH_ENCRYPTION \
+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION \
+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION_LEVEL \
+ FSP_FLAGS_WIDTH_ATOMIC_WRITES )
@@ -292,9 +297,12 @@ it is for a single client and should be deleted upon startup if it exists. */
/** Zero relative shift position of the start of the TEMPORARY bit */
#define FSP_FLAGS_POS_TEMPORARY (FSP_FLAGS_POS_SHARED \
+ FSP_FLAGS_WIDTH_SHARED)
-/** Zero relative shift position of the PAGE_COMPRESSION field */
-#define FSP_FLAGS_POS_PAGE_COMPRESSION (FSP_FLAGS_POS_TEMPORARY \
+/** Zero relative shift position of the start of the ENCRYPTION bit */
+#define FSP_FLAGS_POS_ENCRYPTION (FSP_FLAGS_POS_TEMPORARY \
+ FSP_FLAGS_WIDTH_TEMPORARY)
+/** Zero relative shift position of the PAGE_COMPRESSION field */
+#define FSP_FLAGS_POS_PAGE_COMPRESSION (FSP_FLAGS_POS_ENCRYPTION \
+ + FSP_FLAGS_WIDTH_ENCRYPTION)
/** Zero relative shift position of the PAGE_COMPRESSION_LEVEL field */
#define FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL (FSP_FLAGS_POS_PAGE_COMPRESSION \
+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION)
@@ -302,8 +310,8 @@ it is for a single client and should be deleted upon startup if it exists. */
#define FSP_FLAGS_POS_ATOMIC_WRITES (FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL \
+ FSP_FLAGS_WIDTH_PAGE_COMPRESSION_LEVEL)
/** Zero relative shift position of the start of the UNUSED bits */
-#define FSP_FLAGS_POS_UNUSED (FSP_FLAGS_POS_PAGE_COMPRESSION_LEVEL \
- + FSP_FLAGS_WIDTH_PAGE_COMPRESSION_LEVEL)
+#define FSP_FLAGS_POS_UNUSED (FSP_FLAGS_POS_ATOMIC_WRITES \
+ + FSP_FLAGS_WIDTH_ATOMIC_WRITES)
/** Bit mask of the POST_ANTELOPE field */
@@ -334,6 +342,10 @@ it is for a single client and should be deleted upon startup if it exists. */
#define FSP_FLAGS_MASK_TEMPORARY \
((~(~0U << FSP_FLAGS_WIDTH_TEMPORARY)) \
<< FSP_FLAGS_POS_TEMPORARY)
+/** Bit mask of the ENCRYPTION field */
+#define FSP_FLAGS_MASK_ENCRYPTION \
+ ((~(~0U << FSP_FLAGS_WIDTH_ENCRYPTION)) \
+ << FSP_FLAGS_POS_ENCRYPTION)
/** Bit mask of the PAGE_COMPRESSION field */
#define FSP_FLAGS_MASK_PAGE_COMPRESSION \
((~(~0 << FSP_FLAGS_WIDTH_PAGE_COMPRESSION)) \
@@ -375,6 +387,10 @@ it is for a single client and should be deleted upon startup if it exists. */
#define FSP_FLAGS_GET_TEMPORARY(flags) \
((flags & FSP_FLAGS_MASK_TEMPORARY) \
>> FSP_FLAGS_POS_TEMPORARY)
+/** Return the contents of the ENCRYPTION field */
+#define FSP_FLAGS_GET_ENCRYPTION(flags) \
+ ((flags & FSP_FLAGS_MASK_ENCRYPTION) \
+ >> FSP_FLAGS_POS_ENCRYPTION)
/** Return the contents of the UNUSED bits */
#define FSP_FLAGS_GET_UNUSED(flags) \
(flags >> FSP_FLAGS_POS_UNUSED)
diff --git a/storage/innobase/include/fts0ast.h b/storage/innobase/include/fts0ast.h
index f0f00a40193..87b7cf709c8 100644
--- a/storage/innobase/include/fts0ast.h
+++ b/storage/innobase/include/fts0ast.h
@@ -195,6 +195,13 @@ fts_ast_state_free(
/*===============*/
fts_ast_state_t*state); /*!< in: state instance
to free */
+/** Check only union operation involved in the node
+@param[in] node ast node to check
+@return true if the node contains only union else false. */
+bool
+fts_ast_node_check_union(
+ fts_ast_node_t* node);
+
/******************************************************************//**
Traverse the AST - in-order traversal.
@return DB_SUCCESS if all went well */
diff --git a/storage/innobase/include/fts0fts.h b/storage/innobase/include/fts0fts.h
index 210b9b700e4..2d256472ef6 100644
--- a/storage/innobase/include/fts0fts.h
+++ b/storage/innobase/include/fts0fts.h
@@ -66,7 +66,7 @@ optimize using a 4 byte Doc ID for FIC merge sort to reduce sort size */
#define MAX_DOC_ID_OPT_VAL 1073741824
/** Document id type. */
-typedef ib_uint64_t doc_id_t;
+typedef ib_id_t doc_id_t;
/** doc_id_t printf format */
#define FTS_DOC_ID_FORMAT IB_ID_FMT
@@ -103,7 +103,6 @@ those defined in mysql file ft_global.h */
should not exceed FTS_DOC_ID_MAX_STEP */
#define FTS_DOC_ID_MAX_STEP 65535
-
/** Maximum possible Fulltext word length */
#define FTS_MAX_WORD_LEN HA_FT_MAXBYTELEN
@@ -128,6 +127,7 @@ should not exceed FTS_DOC_ID_MAX_STEP */
/* BLOB COLUMN, 0 means VARIABLE SIZE */
#define FTS_INDEX_ILIST_LEN 0
+
/** Variable specifying the FTS parallel sort degree */
extern ulong fts_sort_pll_degree;
@@ -515,7 +515,7 @@ fts_create_common_tables(
index */
const char* name, /*!< in: table name */
bool skip_doc_id_index) /*!< in: Skip index on doc id */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Wrapper function of fts_create_index_tables_low(), create auxiliary
tables for an FTS index
@@ -526,7 +526,7 @@ fts_create_index_tables(
trx_t* trx, /*!< in: transaction handle */
const dict_index_t* index) /*!< in: the FTS index
instance */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Creates the column specific ancillary tables needed for supporting an
FTS index on the given table. row_mysql_lock_data_dictionary must have
@@ -541,15 +541,14 @@ fts_create_index_tables_low(
instance */
const char* table_name, /*!< in: the table name */
table_id_t table_id) /*!< in: the table id */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Add the FTS document id hidden column. */
void
fts_add_doc_id_column(
/*==================*/
dict_table_t* table, /*!< in/out: Table with FTS index */
- mem_heap_t* heap) /*!< in: temporary memory heap, or NULL */
- MY_ATTRIBUTE((nonnull(1)));
+ mem_heap_t* heap); /*!< in: temporary memory heap, or NULL */
/*********************************************************************//**
Drops the ancillary tables needed for supporting an FTS index on the
@@ -560,9 +559,8 @@ dberr_t
fts_drop_tables(
/*============*/
trx_t* trx, /*!< in: transaction */
- dict_table_t* table) /*!< in: table has the FTS
+ dict_table_t* table); /*!< in: table has the FTS
index */
- MY_ATTRIBUTE((nonnull));
/******************************************************************//**
The given transaction is about to be committed; do whatever is necessary
from the FTS system's POV.
@@ -571,23 +569,27 @@ dberr_t
fts_commit(
/*=======*/
trx_t* trx) /*!< in: transaction */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
-
-/*******************************************************************//**
-FTS Query entry point.
+ MY_ATTRIBUTE((warn_unused_result));
+
+/** FTS Query entry point.
+@param[in] trx transaction
+@param[in] index fts index to search
+@param[in] flags FTS search mode
+@param[in] query_str FTS query
+@param[in] query_len FTS query string len in bytes
+@param[in,out] result result doc ids
+@param[in] limit limit value
@return DB_SUCCESS if successful otherwise error code */
dberr_t
fts_query(
-/*======*/
- trx_t* trx, /*!< in: transaction */
- dict_index_t* index, /*!< in: FTS index to search */
- uint flags, /*!< in: FTS search mode */
- const byte* query, /*!< in: FTS query */
- ulint query_len, /*!< in: FTS query string len
- in bytes */
- fts_result_t** result) /*!< out: query result, to be
- freed by the caller.*/
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ trx_t* trx,
+ dict_index_t* index,
+ uint flags,
+ const byte* query_str,
+ ulint query_len,
+ fts_result_t** result,
+ ulonglong limit)
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Retrieve the FTS Relevance Ranking result for doc with doc_id
@@ -704,8 +706,7 @@ Run OPTIMIZE on the given table.
dberr_t
fts_optimize_table(
/*===============*/
- dict_table_t* table) /*!< in: table to optimiza */
- MY_ATTRIBUTE((nonnull));
+ dict_table_t* table); /*!< in: table to optimiza */
/**********************************************************************//**
Startup the optimize thread and create the work queue. */
@@ -728,7 +729,7 @@ fts_drop_index_tables(
/*==================*/
trx_t* trx, /*!< in: transaction */
dict_index_t* index) /*!< in: Index to drop */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Remove the table from the OPTIMIZER's list. We do wait for
@@ -738,41 +739,32 @@ fts_optimize_remove_table(
/*======================*/
dict_table_t* table); /*!< in: table to remove */
+/** Shutdown fts optimize thread. */
+void
+fts_optimize_shutdown();
+
/** Send sync fts cache for the table.
@param[in] table table to sync */
-UNIV_INTERN
void
fts_optimize_request_sync_table(
dict_table_t* table);
/**********************************************************************//**
-Signal the optimize thread to prepare for shutdown. */
-void
-fts_optimize_start_shutdown(void);
-/*==============================*/
-
-/**********************************************************************//**
-Inform optimize to clean up. */
-void
-fts_optimize_end(void);
-/*===================*/
-
-/**********************************************************************//**
Take a FTS savepoint. */
void
fts_savepoint_take(
/*===============*/
trx_t* trx, /*!< in: transaction */
fts_trx_t* fts_trx, /*!< in: fts transaction */
- const char* name) /*!< in: savepoint name */
- MY_ATTRIBUTE((nonnull));
+ const char* name); /*!< in: savepoint name */
+
/**********************************************************************//**
Refresh last statement savepoint. */
void
fts_savepoint_laststmt_refresh(
/*===========================*/
- trx_t* trx) /*!< in: transaction */
- MY_ATTRIBUTE((nonnull));
+ trx_t* trx); /*!< in: transaction */
+
/**********************************************************************//**
Release the savepoint data identified by name. */
void
@@ -832,19 +824,21 @@ fts_drop_index_split_tables(
/*========================*/
trx_t* trx, /*!< in: transaction */
dict_index_t* index) /*!< in: fts instance */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Run SYNC on the table, i.e., write out data from the cache to the
FTS auxiliary INDEX table and clear the cache at the end.
@param[in,out] table fts table
@param[in] unlock_cache whether unlock cache when write node
@param[in] wait whether wait for existing sync to finish
+@param[in] has_dict whether has dict operation lock
@return DB_SUCCESS on success, error code on failure. */
dberr_t
fts_sync_table(
dict_table_t* table,
bool unlock_cache,
- bool wait);
+ bool wait,
+ bool has_dict);
/****************************************************************//**
Free the query graph but check whether dict_sys->mutex is already
@@ -1027,8 +1021,7 @@ fts_drop_index(
/*===========*/
dict_table_t* table, /*!< in: Table where indexes are dropped */
dict_index_t* index, /*!< in: Index to be dropped */
- trx_t* trx) /*!< in: Transaction for the drop */
- MY_ATTRIBUTE((nonnull));
+ trx_t* trx); /*!< in: Transaction for the drop */
/****************************************************************//**
Rename auxiliary tables for all fts index for a table
@@ -1053,12 +1046,12 @@ fts_check_cached_index(
consistent state. For now consistency is check only by ensuring
index->page_no != FIL_NULL
@param[out] base_table table has host fts index
-@param[in,out] trx trx handler
-@return true if check certifies auxillary tables are sane false otherwise. */
-bool
-fts_is_corrupt(
+@param[in,out] trx trx handler */
+void
+fts_check_corrupt(
dict_table_t* base_table,
trx_t* trx);
+
#endif /*!< fts0fts.h */
diff --git a/storage/innobase/include/fts0priv.h b/storage/innobase/include/fts0priv.h
index f7a2d2c72f2..1fd33c2b103 100644
--- a/storage/innobase/include/fts0priv.h
+++ b/storage/innobase/include/fts0priv.h
@@ -121,7 +121,7 @@ fts_parse_sql(
fts_table_t* fts_table, /*!< in: FTS aux table */
pars_info_t* info, /*!< in: info struct, or NULL */
const char* sql) /*!< in: SQL string to evaluate */
- MY_ATTRIBUTE((nonnull(3), malloc, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Evaluate a parsed SQL statement
@@ -131,7 +131,7 @@ fts_eval_sql(
/*=========*/
trx_t* trx, /*!< in: transaction */
que_t* graph) /*!< in: Parsed statement */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Construct the name of an ancillary FTS table for the given table.
@@ -140,8 +140,9 @@ for param 'table_name'. */
void
fts_get_table_name(
/*===============*/
- const fts_table_t* fts_table, /*!< in: FTS aux table info */
- char* table_name); /*!< in/out: aux table name */
+ const fts_table_t*
+ fts_table, /*!< in: FTS aux table info */
+ char* table_name); /*!< in/out: aux table name */
/******************************************************************//**
Construct the column specification part of the SQL string for selecting the
@@ -164,7 +165,7 @@ fts_get_select_columns_str(
dict_index_t* index, /*!< in: FTS index */
pars_info_t* info, /*!< in/out: parser info */
mem_heap_t* heap) /*!< in: memory heap */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** define for fts_doc_fetch_by_doc_id() "option" value, defines whether
we want to get Doc whose ID is equal to or greater or smaller than supplied
@@ -189,8 +190,7 @@ fts_doc_fetch_by_doc_id(
fts_sql_callback
callback, /*!< in: callback to read
records */
- void* arg) /*!< in: callback arg */
- MY_ATTRIBUTE((nonnull(6)));
+ void* arg); /*!< in: callback arg */
/*******************************************************************//**
Callback function for fetch that stores the text of an FTS document,
@@ -200,8 +200,8 @@ ibool
fts_query_expansion_fetch_doc(
/*==========================*/
void* row, /*!< in: sel_node_t* */
- void* user_arg) /*!< in: fts_doc_t* */
- MY_ATTRIBUTE((nonnull));
+ void* user_arg); /*!< in: fts_doc_t* */
+
/********************************************************************
Write out a single word's data as new entry/entries in the INDEX table.
@return DB_SUCCESS if all OK. */
@@ -213,7 +213,7 @@ fts_write_node(
fts_table_t* fts_table, /*!< in: the FTS aux index */
fts_string_t* word, /*!< in: word in UTF-8 */
fts_node_t* node) /*!< in: node columns */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Check fts token
1. for ngram token, check whether the token contains any words in stopwords
@@ -274,7 +274,7 @@ fts_bsearch(
int lower, /*!< in: lower bound of array*/
int upper, /*!< in: upper bound of array*/
doc_id_t doc_id) /*!< in: doc id to lookup */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Free document. */
void
@@ -359,7 +359,7 @@ fts_parse_sql_no_dict_lock(
fts_table_t* fts_table, /*!< in: table with FTS index */
pars_info_t* info, /*!< in: parser info */
const char* sql) /*!< in: SQL string to evaluate */
- MY_ATTRIBUTE((nonnull(3), malloc, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Get value from config table. The caller must ensure that enough
@@ -388,7 +388,7 @@ fts_config_get_index_value(
this parameter name */
fts_string_t* value) /*!< out: value read from
config table */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Set the value in the config table for name.
@@ -413,7 +413,7 @@ fts_config_set_ulint(
fts_table_t* fts_table, /*!< in: the indexed FTS table */
const char* name, /*!< in: param name */
ulint int_value) /*!< in: value */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Set the value specific to an FTS index in the config table.
@@ -427,7 +427,7 @@ fts_config_set_index_value(
this parameter name */
fts_string_t* value) /*!< out: value read from
config table */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Increment the value in the config table for column name.
@@ -440,7 +440,7 @@ fts_config_increment_value(
const char* name, /*!< in: increment config value
for this parameter name */
ulint delta) /*!< in: increment by this much */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Increment the per index value in the config table for column name.
@@ -464,7 +464,7 @@ fts_config_get_index_ulint(
dict_index_t* index, /*!< in: FTS index */
const char* name, /*!< in: param name */
ulint* int_value) /*!< out: value */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Set an ulint value int the config table.
@@ -476,7 +476,7 @@ fts_config_set_index_ulint(
dict_index_t* index, /*!< in: FTS index */
const char* name, /*!< in: param name */
ulint int_value) /*!< in: value */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Get an ulint value from the config table.
@@ -499,7 +499,7 @@ fts_cache_find_word(
index_cache, /*!< in: cache to search */
const fts_string_t*
text) /*!< in: word to search for */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Check cache for deleted doc id.
@@ -510,7 +510,7 @@ fts_cache_is_deleted_doc_id(
const fts_cache_t*
cache, /*!< in: cache ito search */
doc_id_t doc_id) /*!< in: doc id to search for */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Append deleted doc ids to vector and sort the vector. */
@@ -543,7 +543,7 @@ fts_get_total_word_count(
trx_t* trx, /*!< in: transaction */
dict_index_t* index, /*!< in: for this index */
ulint* total) /*!< out: total words */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif
/******************************************************************//**
Search the index specific cache for a particular FTS index.
@@ -555,7 +555,7 @@ fts_find_index_cache(
cache, /*!< in: cache to search */
const dict_index_t*
index) /*!< in: index to search for */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Write the table id to the given buffer (including final NUL). Buffer must be
@@ -567,10 +567,10 @@ fts_write_object_id(
/*================*/
ib_id_t id, /*!< in: a table/index id */
char* str, /*!< in: buffer to write the id to */
- bool hex_format MY_ATTRIBUTE((unused)))
+ bool hex_format MY_ATTRIBUTE((unused)));
/*!< in: true for fixed hex format,
false for old ambiguous format */
- MY_ATTRIBUTE((nonnull));
+
/******************************************************************//**
Read the table id from the string generated by fts_write_object_id().
@return TRUE if parse successful */
@@ -580,7 +580,7 @@ fts_read_object_id(
/*===============*/
ib_id_t* id, /*!< out: a table id */
const char* str) /*!< in: buffer to read from */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Get the table id.
@@ -593,7 +593,7 @@ fts_get_table_id(
char* table_id) /*!< out: table id, must be at least
FTS_AUX_MIN_TABLE_ID_LENGTH bytes
long */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Add the table to add to the OPTIMIZER's list. */
@@ -617,7 +617,7 @@ fts_get_table_name_prefix(
/*======================*/
const fts_table_t*
fts_table) /*!< in: Auxiliary table type */
- MY_ATTRIBUTE((nonnull, malloc, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Add node positions. */
@@ -637,7 +637,7 @@ fts_config_create_index_param_name(
/*===============================*/
const char* param, /*!< in: base name of param */
const dict_index_t* index) /*!< in: index for config */
- MY_ATTRIBUTE((nonnull, malloc, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_NONINL
#include "fts0priv.ic"
diff --git a/storage/innobase/include/fts0priv.ic b/storage/innobase/include/fts0priv.ic
index 9de3be215dc..fa2cdd44a36 100644
--- a/storage/innobase/include/fts0priv.ic
+++ b/storage/innobase/include/fts0priv.ic
@@ -46,31 +46,26 @@ fts_write_object_id(
/* Use this to construct old(5.6.14 and 5.7.3) windows
ambiguous aux table names */
DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
- return(sprintf(str, "%016llu", id)););
+ return(sprintf(str, "%016llu", (ulonglong) id)););
#else /* _WIN32 */
/* Use this to construct old(5.6.14 and 5.7.3) windows
ambiguous aux table names */
DBUG_EXECUTE_IF("innodb_test_wrong_windows_fts_aux_table_name",
- return(sprintf(str, "%016lu", id)););
+ return(sprintf(str, "%016llu", (ulonglong) id)););
DBUG_EXECUTE_IF("innodb_test_wrong_fts_aux_table_name",
- return(sprintf(str, "%016lx", id)););
+ return(sprintf(str, "%016llx", (ulonglong) id)););
#endif /* _WIN32 */
/* As above, but this is only for those tables failing to rename. */
if (!hex_format) {
-#ifdef _WIN32
- // FIXME: Use ut_snprintf(), so does following one.
- return(sprintf(str, "%016llu", id));
-#else /* _WIN32 */
- return(sprintf(str, "%016lu", id));
-#endif /* _WIN32 */
+ return(sprintf(str, "%016llu", (ulonglong) id));
}
- return(sprintf(str, "%016lx", id));
+ return(sprintf(str, "%016llx", (ulonglong) id));
}
/******************************************************************//**
@@ -86,7 +81,7 @@ fts_read_object_id(
/* NOTE: this func doesn't care about whether current table
is set with HEX_NAME, the user of the id read here will check
if the id is HEX or DEC and do the right thing with it. */
- return(sscanf(str, "%016lx", id) == 1);
+ return(sscanf(str, UINT64PFx, id) == 1);
}
/******************************************************************//**
diff --git a/storage/innobase/include/fut0fut.h b/storage/innobase/include/fut0fut.h
index ab04a700d4f..0b8b8b0e43b 100644
--- a/storage/innobase/include/fut0fut.h
+++ b/storage/innobase/include/fut0fut.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -50,7 +50,7 @@ fut_get_ptr(
rw_lock_type_t rw_latch,
mtr_t* mtr,
buf_block_t** ptr_block = NULL)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_NONINL
#include "fut0fut.ic"
diff --git a/storage/innobase/include/gis0rtree.h b/storage/innobase/include/gis0rtree.h
index 316cab888b3..436374fd6b2 100644
--- a/storage/innobase/include/gis0rtree.h
+++ b/storage/innobase/include/gis0rtree.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -70,7 +70,7 @@ Created 2013/03/27 Jimmy Yang and Allen Lai
/* Define it for rtree search mode checking. */
#define RTREE_SEARCH_MODE(mode) \
- (((mode) >= PAGE_CUR_CONTAIN) && ((mode <= PAGE_CUR_RTREE_LOCATE)))
+ (((mode) >= PAGE_CUR_CONTAIN) && ((mode <= PAGE_CUR_RTREE_GET_FATHER)))
/* Geometry data header */
#define GEO_DATA_HEADER_SIZE 4
@@ -320,6 +320,23 @@ rtr_get_mbr_from_tuple(
#define rtr_page_get_father_node_ptr(of,heap,sea,cur,mtr) \
rtr_page_get_father_node_ptr_func(of,heap,sea,cur,__FILE__,__LINE__,mtr)
+/* Get the rtree page father.
+@param[in] offsets work area for the return value
+@param[in] index rtree index
+@param[in] block child page in the index
+@param[in] mtr mtr
+@param[in] sea_cur search cursor, contains information
+ about parent nodes in search
+@param[in] cursor cursor on node pointer record,
+ its page x-latched */
+void
+rtr_page_get_father(
+ dict_index_t* index,
+ buf_block_t* block,
+ mtr_t* mtr,
+ btr_cur_t* sea_cur,
+ btr_cur_t* cursor);
+
/************************************************************//**
Returns the upper level node pointer to a R-Tree page. It is assumed
that mtr holds an x-latch on the tree.
diff --git a/storage/innobase/include/ha0ha.h b/storage/innobase/include/ha0ha.h
index 11c12c4ebc3..15a99ddf683 100644
--- a/storage/innobase/include/ha0ha.h
+++ b/storage/innobase/include/ha0ha.h
@@ -211,7 +211,7 @@ struct ha_node_t {
#if defined UNIV_AHI_DEBUG || defined UNIV_DEBUG
buf_block_t* block; /*!< buffer block containing the data, or NULL */
#endif /* UNIV_AHI_DEBUG || UNIV_DEBUG */
- const rec_t* data; /*!< pointer to the data */
+ const rec_t* data; /*!< pointer to the data */
};
#ifdef UNIV_DEBUG
diff --git a/storage/innobase/include/ha_prototypes.h b/storage/innobase/include/ha_prototypes.h
index 9bf8cd2b281..837c377f448 100644
--- a/storage/innobase/include/ha_prototypes.h
+++ b/storage/innobase/include/ha_prototypes.h
@@ -37,6 +37,7 @@ simple headers.
class THD;
class Field;
struct fts_string_t;
+//typedef struct charset_info_st CHARSET_INFO;
/*********************************************************************//**
Wrapper around MySQL's copy_and_convert function.
@@ -162,7 +163,7 @@ checkpoint when necessary.*/
UNIV_INTERN
void
innobase_mysql_log_notify(
-/*===============*/
+/*======================*/
ib_uint64_t write_lsn, /*!< in: LSN written to log file */
ib_uint64_t flush_lsn); /*!< in: LSN flushed to disk */
@@ -342,6 +343,14 @@ thd_set_lock_wait_time(
THD* thd, /*!< in/out: thread handle */
ulint value); /*!< in: time waited for the lock */
+/** Get status of innodb_tmpdir.
+@param[in] thd thread handle, or NULL to query
+ the global innodb_tmpdir.
+@retval NULL if innodb_tmpdir="" */
+const char*
+thd_innodb_tmpdir(
+ THD* thd);
+
/**********************************************************************//**
Get the current setting of the table_cache_size global parameter. We do
a dirty read because for one there is no synchronization object and
@@ -531,7 +540,6 @@ innobase_convert_to_system_charset(
const char* from, /* in: identifier to convert */
ulint len, /* in: length of 'to', in bytes */
uint* errors); /* out: error return */
-
/**********************************************************************
Check if the length of the identifier exceeds the maximum allowed.
The input to this function is an identifier in charset my_charset_filename.
@@ -606,7 +614,7 @@ ICP_RESULT
innobase_index_cond(
/*================*/
void* file) /*!< in/out: pointer to ha_innobase */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************************//**
Gets information on the durability property requested by thread.
@@ -625,7 +633,7 @@ enum durability_properties
thd_requested_durability(
/*=====================*/
const THD* thd) /*!< in: thread handle */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Update the system variable with the given value of the InnoDB
buffer pool size.
diff --git a/storage/innobase/include/ibuf0ibuf.h b/storage/innobase/include/ibuf0ibuf.h
index c4d83833fb7..f3fd5e9a364 100644
--- a/storage/innobase/include/ibuf0ibuf.h
+++ b/storage/innobase/include/ibuf0ibuf.h
@@ -244,7 +244,7 @@ ibool
ibuf_inside(
/*========*/
const mtr_t* mtr) /*!< in: mini-transaction */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/** Checks if a page address is an ibuf bitmap page (level 3 page) address.
@param[in] page_id page id
@@ -362,20 +362,16 @@ ibuf_delete_for_discarded_space(
@param[in] full If true, do a full contraction based
on PCT_IO(100). If false, the size of contract batch is determined
based on the current size of the change buffer.
-@param[in] space_id tablespace for which to contract, or
-ULINT_UNDEFINED to contract for all tablespaces
@return a lower limit for the combined size in bytes of entries which
will be merged from ibuf trees to the pages read, 0 if ibuf is
empty */
ulint
ibuf_merge_in_background(
- bool full,
- ulint space_id);
+ bool full);
/** Contracts insert buffer trees by reading pages referring to space_id
to the buffer pool.
@returns number of pages merged.*/
-UNIV_INTERN
ulint
ibuf_merge_space(
/*=============*/
diff --git a/storage/innobase/include/lock0lock.h b/storage/innobase/include/lock0lock.h
index 84050f374fb..eb554e02bc0 100644
--- a/storage/innobase/include/lock0lock.h
+++ b/storage/innobase/include/lock0lock.h
@@ -285,7 +285,7 @@ lock_rec_insert_check_and_lock(
inserted record maybe should inherit
LOCK_GAP type locks from the successor
record */
- MY_ATTRIBUTE((nonnull(2,3,4,6,7), warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Enqueues a waiting request for a lock which cannot be granted immediately.
@@ -381,7 +381,7 @@ lock_clust_rec_modify_check_and_lock(
dict_index_t* index, /*!< in: clustered index */
const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
que_thr_t* thr) /*!< in: query thread */
- MY_ATTRIBUTE((warn_unused_result, nonnull));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Checks if locks of other transactions prevent an immediate modify
(delete mark or delete unmark) of a secondary index record.
@@ -401,7 +401,7 @@ lock_sec_rec_modify_check_and_lock(
que_thr_t* thr, /*!< in: query thread
(can be NULL if BTR_NO_LOCKING_FLAG) */
mtr_t* mtr) /*!< in/out: mini-transaction */
- MY_ATTRIBUTE((warn_unused_result, nonnull(2,3,4,6)));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Like lock_clust_rec_read_check_and_lock(), but reads a
secondary index record.
@@ -485,7 +485,7 @@ lock_clust_rec_read_check_and_lock_alt(
ulint gap_mode,/*!< in: LOCK_ORDINARY, LOCK_GAP, or
LOCK_REC_NOT_GAP */
que_thr_t* thr) /*!< in: query thread */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Checks that a record is seen in a consistent read.
@return true if sees, or false if an earlier version of the record
@@ -511,11 +511,12 @@ clustered index record might be needed */
bool
lock_sec_rec_cons_read_sees(
/*========================*/
- const rec_t* rec, /*!< in: user record which should be read or
- passed over by a read cursor */
- const dict_index_t* index, /*!< in: clustered index */
- const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
- const ReadView* view); /*!< in: consistent read view */
+ const rec_t* rec, /*!< in: user record which
+ should be read or passed over
+ by a read cursor */
+ const dict_index_t* index, /*!< in: index */
+ const ReadView* view) /*!< in: consistent read view */
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Locks the specified database table in the mode given. If the lock cannot
be granted immediately, the query thread is put to wait.
@@ -529,7 +530,7 @@ lock_table(
in dictionary cache */
lock_mode mode, /*!< in: lock mode */
que_thr_t* thr) /*!< in: query thread */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Creates a table IX lock object for a resurrected transaction. */
void
@@ -537,6 +538,19 @@ lock_table_ix_resurrect(
/*====================*/
dict_table_t* table, /*!< in/out: table */
trx_t* trx); /*!< in/out: transaction */
+
+/** Sets a lock on a table based on the given mode.
+@param[in] table table to lock
+@param[in,out] trx transaction
+@param[in] mode LOCK_X or LOCK_S
+@return error code or DB_SUCCESS. */
+dberr_t
+lock_table_for_trx(
+ dict_table_t* table,
+ trx_t* trx,
+ enum lock_mode mode)
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
+
/*************************************************************//**
Removes a granted record lock of a transaction from the queue and grants
locks to other transactions waiting in the queue if they now are entitled
@@ -634,8 +648,7 @@ ibool
lock_is_table_exclusive(
/*====================*/
const dict_table_t* table, /*!< in: table */
- const trx_t* trx) /*!< in: transaction */
- MY_ATTRIBUTE((nonnull));
+ const trx_t* trx); /*!< in: transaction */
/*********************************************************************//**
Checks if a lock request lock1 has to wait for request lock2.
@return TRUE if lock1 has to wait for lock2 to be removed */
@@ -680,7 +693,7 @@ lock_print_info_summary(
/*====================*/
FILE* file, /*!< in: file where to print */
ibool nowait) /*!< in: whether to wait for the lock mutex */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Prints transaction lock wait and MVCC state.
@param[in,out] file file where to print
@@ -707,7 +720,7 @@ ulint
lock_number_of_rows_locked(
/*=======================*/
const trx_lock_t* trx_lock) /*!< in: transaction locks */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Return the number of table locks for a transaction.
@@ -716,7 +729,7 @@ ulint
lock_number_of_tables_locked(
/*=========================*/
const trx_lock_t* trx_lock) /*!< in: transaction locks */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Gets the type of a lock. Non-inline version for using outside of the
@@ -900,7 +913,7 @@ lock_check_trx_id_sanity(
const rec_t* rec, /*!< in: user record */
dict_index_t* index, /*!< in: index */
const ulint* offsets) /*!< in: rec_get_offsets(rec, index) */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Check if the transaction holds any locks on the sys tables
or its records.
@@ -921,7 +934,7 @@ lock_trx_has_rec_x_lock(
const dict_table_t* table, /*!< in: table to check */
const buf_block_t* block, /*!< in: buffer block of the record */
ulint heap_no)/*!< in: record heap number */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */
/**
@@ -1141,6 +1154,7 @@ lock_update_split_and_merge(
const buf_block_t* right_block);/*!< in: right page from which merged */
#endif /* WITH_WSREP */
+
#ifndef UNIV_NONINL
#include "lock0lock.ic"
#endif
diff --git a/storage/innobase/include/lock0prdt.h b/storage/innobase/include/lock0prdt.h
index 8941a134a8f..6c61f07a4e8 100644
--- a/storage/innobase/include/lock0prdt.h
+++ b/storage/innobase/include/lock0prdt.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -203,22 +203,25 @@ lock_prdt_rec_move(
const buf_block_t* donator); /*!< in: buffer block containing
the donating record */
-/*********************************************************************//**
-Check whether there are R-tree Page lock on a buffer page
+/** Check whether there are R-tree Page lock on a buffer page
+@param[in] trx trx to test the lock
+@param[in] space space id for the page
+@param[in] page_no page number
@return true if there is none */
bool
lock_test_prdt_page_lock(
/*=====================*/
- ulint space, /*!< in: space id for the page */
- ulint page_no); /*!< in: page number */
+ const trx_t* trx,
+ ulint space,
+ ulint page_no);
-/*************************************************************//**
-Removes predicate lock objects set on an index page which is discarded. */
+/** Removes predicate lock objects set on an index page which is discarded.
+@param[in] block page to be discarded
+@param[in] lock_hash lock hash */
void
-lock_prdt_free_from_discard_page(
+lock_prdt_page_free_from_discard(
/*=============================*/
- const buf_block_t* block, /*!< in: page to be discarded */
+ const buf_block_t* block,
hash_table_t* lock_hash);
- /*!< in: lock hash */
#endif
diff --git a/storage/innobase/include/lock0priv.h b/storage/innobase/include/lock0priv.h
index 06573d261fb..0b2ab1bfcfe 100644
--- a/storage/innobase/include/lock0priv.h
+++ b/storage/innobase/include/lock0priv.h
@@ -729,20 +729,23 @@ public:
Create a lock for a transaction and initialise it.
@param[in, out] trx Transaction requesting the new lock
@param[in] owns_trx_mutex true if caller owns the trx_t::mutex
+ @param[in] add_to_hash add the lock to hash table
@param[in] prdt Predicate lock (optional)
@return new lock instance */
lock_t* create(
trx_t* trx,
bool owns_trx_mutex,
+ bool add_to_hash,
const lock_prdt_t*
prdt = NULL);
+
lock_t* create(
lock_t* const c_lock,
trx_t* trx,
bool owns_trx_mutex,
+ bool add_to_hash,
const lock_prdt_t*
prdt = NULL);
-
/**
Check of the lock is on m_rec_id.
@param[in] lock Lock to compare with
@@ -765,19 +768,6 @@ public:
ulint size);
private:
- /**
- Enqueue a lock wait for a high priority transaction, jump the record
- lock wait queue and if the transaction at the head of the queue is
- itself waiting roll it back.
- @param[in, out] wait_for The lock that the joining
- transaction is waiting for
- @param[in] prdt Predicate for the predicate lock
- @return NULL if the lock was granted */
- lock_t* enqueue_priority(
- const lock_t* wait_for,
- const lock_prdt_t*
- prdt);
-
/*
@return the record lock size in bytes */
size_t lock_size() const
@@ -795,15 +785,47 @@ private:
void mark_trx_for_rollback(trx_t* trx);
/**
- Add the lock to the head of the record lock {space, page_no} wait
- queue and the transaction's lock list. If the transactions holding
- blocking locks are already marked for termination then they are not
- added to the hit list.
- @param[in, out] lock Lock being requested
- @param[in] wait_for The blocking lock
- @param[in] kill_trx true if the transaction that m_trx
- is waiting for should be killed */
- void jump_queue(lock_t* lock, const lock_t* wait_for, bool kill_trx);
+ Jump the queue for the record over all low priority transactions and
+ add the lock. If all current granted locks are compatible, grant the
+ lock. Otherwise, mark all granted transaction for asynchronous
+ rollback and add to hit list.
+ @param[in, out] lock Lock being requested
+ @param[in] conflict_lock First conflicting lock from the head
+ @return true if the lock is granted */
+ bool jump_queue(lock_t* lock, const lock_t* conflict_lock);
+
+ /** Find position in lock queue and add the high priority transaction
+ lock. Intention and GAP only locks can be granted even if there are
+ waiting locks in front of the queue. To add the High priority
+ transaction in a safe position we keep the following rule.
+
+ 1. If the lock can be granted, add it before the first waiting lock
+ in the queue so that all currently waiting locks need to do conflict
+ check before getting granted.
+
+ 2. If the lock has to wait, add it after the last granted lock or the
+ last waiting high priority transaction in the queue whichever is later.
+ This ensures that the transaction is granted only after doing conflict
+ check with all granted transactions.
+ @param[in] lock Lock being requested
+ @param[in] conflict_lock First conflicting lock from the head
+ @param[out] high_priority high priority transaction ahead in queue
+ @return true if the lock can be granted */
+ bool
+ lock_add_priority(
+ lock_t* lock,
+ const lock_t* conflict_lock,
+ bool* high_priority);
+
+ /** Iterate over the granted locks and prepare the hit list for ASYNC Rollback.
+ If the transaction is waiting for some other lock then wake up with deadlock error.
+ Currently we don't mark following transactions for ASYNC Rollback.
+ 1. Read only transactions
+ 2. Background transactions
+ 3. Other High priority transactions
+ @param[in] lock Lock being requested
+ @param[in] conflict_lock First conflicting lock from the head */
+ void make_trx_hit_list(lock_t* lock, const lock_t* conflict_lock);
/**
Setup the requesting transaction state for lock grant
@@ -811,11 +833,6 @@ private:
void set_wait_state(lock_t* lock);
/**
- Rollback the transaction that is blocking the requesting transaction
- @param[in, out] lock The blocking lock */
- void rollback_blocking_trx(lock_t* lock) const;
-
- /**
Add the lock to the record lock hash and the transaction's lock list
@param[in,out] lock Newly created record lock to add to the
rec hash and the transaction lock list
@@ -987,7 +1004,7 @@ lock_clust_rec_some_has_impl(
const rec_t* rec, /*!< in: user record */
const dict_index_t* index, /*!< in: clustered index */
const ulint* offsets)/*!< in: rec_get_offsets(rec, index) */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Gets the first or next record lock on a page.
diff --git a/storage/innobase/include/log0log.h b/storage/innobase/include/log0log.h
index e67eef4a26c..c1f25704217 100644
--- a/storage/innobase/include/log0log.h
+++ b/storage/innobase/include/log0log.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All rights reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All rights reserved.
Copyright (c) 2009, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -39,11 +39,7 @@ Created 12/9/1995 Heikki Tuuri
#include "sync0rw.h"
#endif /* !UNIV_HOTBACKUP */
#include "log0crypt.h"
-
-
-#define LSN_MAX IB_UINT64_MAX
-
-#define LSN_PF UINT64PF
+#include "log0types.h"
/** Redo log buffer */
struct log_t;
@@ -178,7 +174,7 @@ log_init(void);
/******************************************************************//**
Inits a log group to the log system.
@return true if success, false if not */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
bool
log_group_init(
/*===========*/
@@ -564,7 +560,9 @@ or the MySQL version that created the redo log file. */
/** The redo log format identifier corresponding to the current format version.
Stored in LOG_HEADER_FORMAT. */
#define LOG_HEADER_FORMAT_CURRENT 1
-/* @} */
+
+// JAN: TODO: Shoud 32 here be LOG_HEADER_CREATOR_END ?
+// Problem: Log format 5.6 == 5.7 ?
#define LOG_CHECKPOINT_ARRAY_END (32 + 32 * 8)
#define LOG_CRYPT_VER (20 + LOG_CHECKPOINT_ARRAY_END)
#define LOG_CRYPT_MAX_ENTRIES (5)
@@ -575,6 +573,7 @@ Stored in LOG_HEADER_FORMAT. */
#define LOG_CHECKPOINT_SIZE (20 + LOG_CHECKPOINT_ARRAY_END + \
LOG_CRYPT_SIZE)
+/* @} */
#define LOG_CHECKPOINT_1 OS_FILE_LOG_BLOCK_SIZE
/* first checkpoint field in the log
@@ -600,7 +599,9 @@ typedef ib_mutex_t FlushOrderMutex;
/** Log group consists of a number of log files, each of the same size; a log
group is implemented as a space in the sense of the module fil0fil.
-The fields are protected by log_sys->mutex. */
+Currently, this is only protected by log_sys->mutex. However, in the case
+of log_write_up_to(), we will access some members only with the protection
+of log_sys->write_mutex, which should affect nothing for now. */
struct log_group_t{
/** log group identifier (always 0) */
ulint id;
@@ -642,11 +643,14 @@ struct log_t{
same memory cache line */
lsn_t lsn; /*!< log sequence number */
ulint buf_free; /*!< first free offset within the log
- buffer */
+ buffer in use */
#ifndef UNIV_HOTBACKUP
char pad2[CACHE_LINE_SIZE];/*!< Padding */
LogSysMutex mutex; /*!< mutex protecting the log */
- char pad3[CACHE_LINE_SIZE];/*!< Padding */
+ char pad3[CACHE_LINE_SIZE]; /*!< Padding */
+ LogSysMutex write_mutex; /*!< mutex protecting writing to log
+ file and accessing to log_group_t */
+ char pad4[CACHE_LINE_SIZE];/*!< Padding */
FlushOrderMutex log_flush_order_mutex;/*!< mutex to serialize access to
the flush list when we are putting
dirty blocks in the list. The idea
@@ -656,12 +660,22 @@ struct log_t{
insertions in the flush_list happen
in the LSN order. */
#endif /* !UNIV_HOTBACKUP */
- byte* buf_ptr; /* unaligned log buffer */
- byte* buf; /*!< log buffer */
- ulint buf_size; /*!< log buffer size in bytes */
+ byte* buf_ptr; /*!< unaligned log buffer, which should
+ be of double of buf_size */
+ byte* buf; /*!< log buffer currently in use;
+ this could point to either the first
+ half of the aligned(buf_ptr) or the
+ second half in turns, so that log
+ write/flush to disk don't block
+ concurrent mtrs which will write
+ log to this buffer */
+ bool first_in_use; /*!< true if buf points to the first
+ half of the aligned(buf_ptr), false
+ if the second half */
+ ulint buf_size; /*!< log buffer size of each in bytes */
ulint max_buf_free; /*!< recommended maximum value of
- buf_free, after which the buffer is
- flushed */
+ buf_free for the buffer in use, after
+ which the buffer is flushed */
bool check_flush_or_checkpoint;
/*!< this is set when there may
be need to flush the log buffer, or
@@ -687,11 +701,6 @@ struct log_t{
volatile bool is_extending; /*!< this is set to true during extend
the log buffer size */
lsn_t write_lsn; /*!< last written lsn */
- ulint write_end_offset;/*!< the data in buffer has
- been written up to this offset
- when the current write ends:
- this field will then be copied
- to buf_next_to_write */
lsn_t current_flush_lsn;/*!< end lsn for the current running
write + flush operation */
lsn_t flushed_to_disk_lsn;
@@ -786,12 +795,33 @@ struct log_t{
/** Test if log sys mutex is owned. */
#define log_mutex_own() mutex_own(&log_sys->mutex)
+/** Test if log sys write mutex is owned. */
+#define log_write_mutex_own() mutex_own(&log_sys->write_mutex)
+
/** Acquire the log sys mutex. */
#define log_mutex_enter() mutex_enter(&log_sys->mutex)
+/** Acquire the log sys write mutex. */
+#define log_write_mutex_enter() mutex_enter(&log_sys->write_mutex)
+
+/** Acquire all the log sys mutexes. */
+#define log_mutex_enter_all() do { \
+ mutex_enter(&log_sys->write_mutex); \
+ mutex_enter(&log_sys->mutex); \
+} while (0)
+
/** Release the log sys mutex. */
#define log_mutex_exit() mutex_exit(&log_sys->mutex)
+/** Release the log sys write mutex.*/
+#define log_write_mutex_exit() mutex_exit(&log_sys->write_mutex)
+
+/** Release all the log sys mutexes. */
+#define log_mutex_exit_all() do { \
+ mutex_exit(&log_sys->mutex); \
+ mutex_exit(&log_sys->write_mutex); \
+} while (0)
+
/** Calculate the offset of an lsn within a log group.
@param[in] lsn log sequence number
@param[in] group log group
diff --git a/storage/innobase/include/log0log.ic b/storage/innobase/include/log0log.ic
index caf497606d8..a53f8770cea 100644
--- a/storage/innobase/include/log0log.ic
+++ b/storage/innobase/include/log0log.ic
@@ -439,15 +439,14 @@ Gets the last lsn that is fully flushed to disk.
UNIV_INLINE
ib_uint64_t
log_get_flush_lsn(void)
-/*=============*/
{
ib_uint64_t lsn;
- mutex_enter(&(log_sys->mutex));
+ log_mutex_enter();
lsn = log_sys->flushed_to_disk_lsn;
- mutex_exit(&(log_sys->mutex));
+ log_mutex_exit();
return(lsn);
}
@@ -458,7 +457,7 @@ Gets the current lsn with a trylock
UNIV_INLINE
lsn_t
log_get_lsn_nowait(void)
-/*=============*/
+/*====================*/
{
lsn_t lsn=0;
diff --git a/storage/innobase/include/log0recv.h b/storage/innobase/include/log0recv.h
index 85b326e6500..bd7118654f3 100644
--- a/storage/innobase/include/log0recv.h
+++ b/storage/innobase/include/log0recv.h
@@ -35,6 +35,7 @@ Created 9/20/1997 Heikki Tuuri
#include "ut0new.h"
#include <list>
+#include <vector>
#ifdef UNIV_HOTBACKUP
extern bool recv_replay_file_ops;
@@ -278,6 +279,16 @@ struct recv_dblwr_t {
list pages;
};
+/* Recovery encryption information */
+typedef struct recv_encryption {
+ ulint space_id; /*!< the page number */
+ byte* key; /*!< encryption key */
+ byte* iv; /*!< encryption iv */
+} recv_encryption_t;
+
+typedef std::vector<recv_encryption_t, ut_allocator<recv_encryption_t> >
+ encryption_list_t;
+
/** Recovery system data structure */
struct recv_sys_t{
#ifndef UNIV_HOTBACKUP
@@ -346,6 +357,9 @@ struct recv_sys_t{
addresses in the hash table */
recv_dblwr_t dblwr;
+
+ encryption_list_t* /*!< Encryption information list */
+ encryption_list;
};
/** The recovery system */
@@ -404,7 +418,7 @@ extern ulint recv_n_pool_free_frames;
/******************************************************//**
Checks the 4-byte checksum to the trailer checksum field of a log
block. */
-ibool
+bool
log_block_checksum_is_ok(
/*===================================*/
const byte* block, /*!< in: pointer to a log block */
diff --git a/storage/innobase/include/mach0data.h b/storage/innobase/include/mach0data.h
index 07e23139542..4d32e2e7170 100644
--- a/storage/innobase/include/mach0data.h
+++ b/storage/innobase/include/mach0data.h
@@ -53,7 +53,7 @@ ulint
mach_read_from_1(
/*=============*/
const byte* b) /*!< in: pointer to byte */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in two consecutive
bytes. We store the most significant byte to the lower address. */
@@ -72,7 +72,7 @@ ulint
mach_read_from_2(
/*=============*/
const byte* b) /*!< in: pointer to two bytes */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************//**
The following function is used to convert a 16-bit data item
@@ -114,7 +114,7 @@ ulint
mach_read_from_3(
/*=============*/
const byte* b) /*!< in: pointer to 3 bytes */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in four consecutive
bytes. We store the most significant byte to the lowest address. */
@@ -133,7 +133,7 @@ ulint
mach_read_from_4(
/*=============*/
const byte* b) /*!< in: pointer to four bytes */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a ulint in a compressed form (1..5 bytes).
@return stored size in bytes */
@@ -159,8 +159,7 @@ advanced by the number of bytes consumed
UNIV_INLINE
ib_uint32_t
mach_read_next_compressed(
- const byte** b)
- MY_ATTRIBUTE((nonnull, pure));
+ const byte** b);
/*******************************************************//**
The following function is used to store data in 6 consecutive
bytes. We store the most significant byte to the lowest address. */
@@ -179,7 +178,7 @@ ib_uint64_t
mach_read_from_6(
/*=============*/
const byte* b) /*!< in: pointer to 6 bytes */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in 7 consecutive
bytes. We store the most significant byte to the lowest address. */
@@ -198,7 +197,7 @@ ib_uint64_t
mach_read_from_7(
/*=============*/
const byte* b) /*!< in: pointer to 7 bytes */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************//**
The following function is used to store data in 8 consecutive
bytes. We store the most significant byte to the lowest address. */
@@ -217,7 +216,7 @@ ib_uint64_t
mach_read_from_8(
/*=============*/
const byte* b) /*!< in: pointer to 8 bytes */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a 64-bit integer in a compressed form (5..9 bytes).
@return size in bytes */
@@ -252,7 +251,7 @@ ib_uint64_t
mach_u64_read_much_compressed(
/*==========================*/
const byte* b) /*!< in: pointer to memory from where to read */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/** Read a 32-bit integer in a compressed form.
@param[in,out] ptr pointer to memory where to read;
advanced by the number of bytes consumed, or set NULL if out of space
@@ -281,7 +280,7 @@ double
mach_double_read(
/*=============*/
const byte* b) /*!< in: pointer to memory from where to read */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a double. It is stored in a little-endian format. */
UNIV_INLINE
@@ -298,7 +297,7 @@ float
mach_float_read(
/*============*/
const byte* b) /*!< in: pointer to memory from where to read */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a float. It is stored in a little-endian format. */
UNIV_INLINE
@@ -316,7 +315,7 @@ mach_read_from_n_little_endian(
/*===========================*/
const byte* buf, /*!< in: from where to read */
ulint buf_size) /*!< in: from how many bytes to read */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a ulint in the little-endian format. */
UNIV_INLINE
@@ -334,7 +333,7 @@ ulint
mach_read_from_2_little_endian(
/*===========================*/
const byte* buf) /*!< in: from where to read */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************//**
Writes a ulint in the little-endian format. */
UNIV_INLINE
@@ -387,7 +386,7 @@ ulint
mach_read_ulint(
const byte* ptr,
mlog_id_t type)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
#endif /* !UNIV_INNOCHECKSUM */
diff --git a/storage/innobase/include/mach0data.ic b/storage/innobase/include/mach0data.ic
index 88c88cf2e76..ece4a37bcce 100644
--- a/storage/innobase/include/mach0data.ic
+++ b/storage/innobase/include/mach0data.ic
@@ -42,6 +42,7 @@ mach_write_to_1(
b[0] = (byte) n;
}
+
#endif /* !UNIV_INNOCHECKSUM */
/*******************************************************//**
@@ -948,4 +949,3 @@ mach_read_ulint(
#endif /* !UNIV_HOTBACKUP */
#endif /* !UNIV_INNOCHECKSUM */
-
diff --git a/storage/innobase/include/mem0mem.h b/storage/innobase/include/mem0mem.h
index 72791e23574..f8fdb53e132 100644
--- a/storage/innobase/include/mem0mem.h
+++ b/storage/innobase/include/mem0mem.h
@@ -207,7 +207,7 @@ mem_heap_is_top(
mem_heap_t* heap,
const void* buf,
ulint buf_sz)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*****************************************************************//**
Allocate a new chunk of memory from a memory heap, possibly discarding
diff --git a/storage/innobase/include/mem0mem.ic b/storage/innobase/include/mem0mem.ic
index d20a1647654..3b4109ee52d 100644
--- a/storage/innobase/include/mem0mem.ic
+++ b/storage/innobase/include/mem0mem.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/include/mtr0log.ic b/storage/innobase/include/mtr0log.ic
index 07aa08ed9df..4015fe36d19 100644
--- a/storage/innobase/include/mtr0log.ic
+++ b/storage/innobase/include/mtr0log.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -214,11 +214,8 @@ mlog_write_initial_log_record_fast(
ulint space;
ulint offset;
- ut_ad(mtr->memo_contains_page_flagged(
- ptr,
- MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX));
-
- ut_ad(ptr && log_ptr);
+ ut_ad(log_ptr);
+ ut_d(mtr->memo_modify_page(ptr));
page = (const byte*) ut_align_down(ptr, UNIV_PAGE_SIZE);
space = mach_read_from_4(page + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
@@ -247,18 +244,7 @@ mlog_write_initial_log_record_fast(
}
}
- log_ptr = mlog_write_initial_log_record_low(
- type, space, offset, log_ptr, mtr);
-
-#ifdef UNIV_DEBUG
- /* We now assume that all x-latched pages have been modified! */
- buf_block_t* block = (buf_block_t*) buf_block_align(ptr);
-
- if (!mtr->memo_contains(mtr->get_memo(), block, MTR_MEMO_MODIFY)) {
- mtr->memo_push(block, MTR_MEMO_MODIFY);
- }
-#endif /* UNIV_DEBUG */
-
- return(log_ptr);
+ return(mlog_write_initial_log_record_low(type, space, offset,
+ log_ptr, mtr));
}
#endif /* !UNIV_HOTBACKUP */
diff --git a/storage/innobase/include/mtr0mtr.h b/storage/innobase/include/mtr0mtr.h
index d3aa191c27a..4a1d867015d 100644
--- a/storage/innobase/include/mtr0mtr.h
+++ b/storage/innobase/include/mtr0mtr.h
@@ -37,7 +37,6 @@ Created 11/26/1995 Heikki Tuuri
/** Start a mini-transaction. */
#define mtr_start(m) (m)->start()
-
/** Start a mini-transaction. */
#define mtr_start_trx(m, t) (m)->start((t))
@@ -105,8 +104,7 @@ savepoint. */
/** Check if memo contains the given page.
@return TRUE if contains */
#define mtr_memo_contains_page(m, p, t) \
- (m)->memo_contains_page( \
- (m)->get_memo(), (p), (t))
+ (m)->memo_contains_page_flagged((p), (t))
#endif /* UNIV_DEBUG */
/** Print info of an mtr handle. */
@@ -280,7 +278,7 @@ struct mtr_t {
/** Return current size of the buffer.
@return savepoint */
ulint get_savepoint() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(is_active());
ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
@@ -310,7 +308,7 @@ struct mtr_t {
/** Get the logging mode.
@return logging mode */
inline mtr_log_t get_log_mode() const
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Change the logging mode.
@param mode logging mode
@@ -379,7 +377,7 @@ struct mtr_t {
@param type) MLOG_1BYTE, MLOG_2BYTES, MLOG_4BYTES
@return value read */
inline ulint read_ulint(const byte* ptr, mlog_id_t type) const
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Locks a rw-latch in S mode.
NOTE: use mtr_s_lock().
@@ -418,6 +416,10 @@ struct mtr_t {
@param type object type: MTR_MEMO_S_LOCK, ...
@return bool if lock released */
bool memo_release(const void* object, ulint type);
+ /** Release a page latch.
+ @param[in] ptr pointer to within a page frame
+ @param[in] type object type: MTR_MEMO_PAGE_X_FIX, ... */
+ void release_page(const void* ptr, mtr_memo_type_t type);
/** Note that the mini-transaction has modified data. */
void set_modified()
@@ -494,18 +496,7 @@ struct mtr_t {
mtr_buf_t* memo,
const void* object,
ulint type)
- __attribute__((warn_unused_result));
-
- /** Check if memo contains the given page.
- @param memo memo stack
- @param ptr pointer to buffer frame
- @param type type of object
- @return true if contains */
- static bool memo_contains_page(
- mtr_buf_t* memo,
- const byte* ptr,
- ulint type)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Check if memo contains the given item.
@param object object to search
@@ -515,11 +506,18 @@ struct mtr_t {
bool memo_contains_flagged(const void* ptr, ulint flags) const;
/** Check if memo contains the given page.
- @param ptr buffer frame
- @param flags specify types of object with OR of
+ @param[in] ptr pointer to within buffer frame
+ @param[in] flags specify types of object with OR of
MTR_MEMO_PAGE_S_FIX... values
- @return true if contains */
- bool memo_contains_page_flagged(const byte* ptr, ulint flags) const;
+ @return the block
+ @retval NULL if not found */
+ buf_block_t* memo_contains_page_flagged(
+ const byte* ptr,
+ ulint flags) const;
+
+ /** Mark the given latched page as modified.
+ @param[in] ptr pointer to within buffer frame */
+ void memo_modify_page(const byte* ptr);
/** Print info of an mtr handle. */
void print() const;
@@ -594,7 +592,7 @@ struct mtr_t {
@param block block being x-fixed
@return true if the mtr is dirtying a clean page. */
static bool is_block_dirtied(const buf_block_t* block)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
private:
/** Look up the system tablespace. */
diff --git a/storage/innobase/include/mtr0mtr.ic b/storage/innobase/include/mtr0mtr.ic
index 6c61f8da9f0..b3d9b052d52 100644
--- a/storage/innobase/include/mtr0mtr.ic
+++ b/storage/innobase/include/mtr0mtr.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/include/os0atomic.h b/storage/innobase/include/os0atomic.h
index 1368176d0b8..7ac429cfc14 100644
--- a/storage/innobase/include/os0atomic.h
+++ b/storage/innobase/include/os0atomic.h
@@ -1,5 +1,5 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -208,6 +208,8 @@ amount to decrement. There is no atomic substract function on Windows */
Returns true if swapped, ptr is pointer to target, old_val is value to
compare to, new_val is the value to swap in. */
+#if defined(HAVE_GCC_SYNC_BUILTINS)
+
# define os_compare_and_swap(ptr, old_val, new_val) \
__sync_bool_compare_and_swap(ptr, old_val, new_val)
@@ -220,9 +222,63 @@ compare to, new_val is the value to swap in. */
# define os_compare_and_swap_uint32(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
+#else
+
+UNIV_INLINE
+bool
+os_compare_and_swap_ulint(volatile ulint* ptr, ulint old_val, ulint new_val)
+{
+#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
+ return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+#else
+ return __sync_bool_compare_and_swap(ptr, old_val, new_val);
+#endif
+}
+
+UNIV_INLINE
+bool
+os_compare_and_swap_lint(volatile lint* ptr, lint old_val, lint new_val)
+{
+#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
+ return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+#else
+ return __sync_bool_compare_and_swap(ptr, old_val, new_val);
+#endif
+}
+
+UNIV_INLINE
+bool
+os_compare_and_swap_uint32(volatile ib_uint32_t* ptr, ib_uint32_t old_val, ib_uint32_t new_val)
+{
+#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
+ return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+#else
+ return __sync_bool_compare_and_swap(ptr, old_val, new_val);
+#endif
+}
+
+#endif /* HAVE_GCC_SYNC_BUILTINS */
+
# ifdef HAVE_IB_ATOMIC_PTHREAD_T_GCC
+#if defined(HAVE_GCC_SYNC_BUILTINS)
# define os_compare_and_swap_thread_id(ptr, old_val, new_val) \
os_compare_and_swap(ptr, old_val, new_val)
+#else
+UNIV_INLINE
+bool
+os_compare_and_swap_thread_id(volatile os_thread_id_t* ptr, os_thread_id_t old_val, os_thread_id_t new_val)
+{
+#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
+ return __atomic_compare_exchange_n(ptr, &old_val, new_val, 0,
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+#else
+ return __sync_bool_compare_and_swap(ptr, old_val, new_val);
+#endif
+}
+#endif /* HAVE_GCC_SYNC_BUILTINS */
# define INNODB_RW_LOCKS_USE_ATOMICS
# define IB_ATOMICS_STARTUP_MSG \
"Mutexes and rw_locks use GCC atomic builtins"
@@ -235,8 +291,19 @@ compare to, new_val is the value to swap in. */
Returns the resulting value, ptr is pointer to target, amount is the
amount of increment. */
+#if defined(HAVE_GCC_SYNC_BUILTINS)
+# define os_atomic_increment(ptr, amount) \
+ __sync_add_and_fetch(ptr, amount)
+#else
+#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
+# define os_atomic_increment(ptr, amount) \
+ __atomic_add_fetch(ptr, amount, __ATOMIC_SEQ_CST)
+#else
# define os_atomic_increment(ptr, amount) \
__sync_add_and_fetch(ptr, amount)
+#endif
+
+#endif /* HAVE_GCC_SYNC_BUILTINS */
# define os_atomic_increment_lint(ptr, amount) \
os_atomic_increment(ptr, amount)
@@ -253,8 +320,18 @@ amount of increment. */
/* Returns the resulting value, ptr is pointer to target, amount is the
amount to decrement. */
+#if defined(HAVE_GCC_SYNC_BUILTINS)
+# define os_atomic_decrement(ptr, amount) \
+ __sync_sub_and_fetch(ptr, amount)
+#else
+#ifdef HAVE_IB_GCC_ATOMIC_SEQ_CST
+# define os_atomic_decrement(ptr, amount) \
+ __atomic_sub_fetch(ptr, amount, __ATOMIC_SEQ_CST)
+#else
# define os_atomic_decrement(ptr, amount) \
__sync_sub_and_fetch(ptr, amount)
+#endif
+#endif /* HAVE_GCC_SYNC_BUILTINS */
# define os_atomic_decrement_lint(ptr, amount) \
os_atomic_decrement(ptr, amount)
diff --git a/storage/innobase/include/os0atomic.ic b/storage/innobase/include/os0atomic.ic
index 651f7b512c9..1f1c460bc47 100644
--- a/storage/innobase/include/os0atomic.ic
+++ b/storage/innobase/include/os0atomic.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -152,7 +152,11 @@ os_atomic_test_and_set(
/* Silence a compiler warning about unused ptr. */
(void) ptr;
+#if defined(__powerpc__) || defined(__aarch64__)
+ __atomic_exchange(ptr, &new_val, &ret, __ATOMIC_SEQ_CST);
+#else
__atomic_exchange(ptr, &new_val, &ret, __ATOMIC_RELEASE);
+#endif
return(ret);
}
@@ -172,8 +176,13 @@ os_atomic_val_compare_and_swap(
/* Silence a compiler warning about unused ptr. */
(void) ptr;
+#if defined(__powerpc__) || defined(__aarch64__)
+ __atomic_compare_exchange(ptr, &old_val, &new_val, false,
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+#else
__atomic_compare_exchange(ptr, &old_val, &new_val, false,
__ATOMIC_RELEASE, __ATOMIC_ACQUIRE);
+#endif
return(old_val);
}
diff --git a/storage/innobase/include/os0file.h b/storage/innobase/include/os0file.h
index 5aa1843c236..5e36cfc2ac0 100644
--- a/storage/innobase/include/os0file.h
+++ b/storage/innobase/include/os0file.h
@@ -137,6 +137,7 @@ static const ulint OS_FILE_READ_WRITE = 444;
/** Used by MySQLBackup */
static const ulint OS_FILE_READ_ALLOW_DELETE = 555;
+
/* Options for file_create */
static const ulint OS_FILE_AIO = 61;
static const ulint OS_FILE_NORMAL = 62;
@@ -154,6 +155,7 @@ static const ulint OS_FILE_NOT_FOUND = 71;
static const ulint OS_FILE_DISK_FULL = 72;
static const ulint OS_FILE_ALREADY_EXISTS = 73;
static const ulint OS_FILE_PATH_ERROR = 74;
+
/** wait for OS aio resources to become available again */
static const ulint OS_FILE_AIO_RESOURCES_RESERVED = 75;
@@ -230,32 +232,32 @@ struct Compression {
@param[in] page Page contents
@return true if it is a compressed page */
static bool is_compressed_page(const byte* page)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Check wether the compression algorithm is supported.
@param[in] algorithm Compression algorithm to check
@param[out] type The type that algorithm maps to
@return DB_SUCCESS or error code */
static dberr_t check(const char* algorithm, Compression* type)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Validate the algorithm string.
@param[in] algorithm Compression algorithm to check
@return DB_SUCCESS or error code */
static dberr_t validate(const char* algorithm)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Convert to a "string".
@param[in] type The compression type
@return the string representation */
static const char* to_string(Type type)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Convert the meta data to a std::string.
@param[in] meta Page Meta data
@return the string representation */
static std::string to_string(const meta_t& meta)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Deserizlise the page header compression meta-data
@param[in] header Pointer to the page header
@@ -268,7 +270,7 @@ struct Compression {
@param[in] algorithm Compression algorithm to check
@return true if no algorithm requested */
static bool is_none(const char* algorithm)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Decompress the page data contents. Page type must be
FIL_PAGE_COMPRESSED, if not then the source contents are
@@ -285,12 +287,215 @@ struct Compression {
byte* src,
byte* dst,
ulint dst_len)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Compression type */
Type m_type;
};
+/** Encryption key length */
+static const ulint ENCRYPTION_KEY_LEN = 32;
+
+/** Encryption magic bytes size */
+static const ulint ENCRYPTION_MAGIC_SIZE = 3;
+
+/** Encryption magic bytes for 5.7.11, it's for checking the encryption information
+version. */
+static const char ENCRYPTION_KEY_MAGIC_V1[] = "lCA";
+
+/** Encryption magic bytes for 5.7.12+, it's for checking the encryption information
+version. */
+static const char ENCRYPTION_KEY_MAGIC_V2[] = "lCB";
+
+/** Encryption master key prifix */
+static const char ENCRYPTION_MASTER_KEY_PRIFIX[] = "INNODBKey";
+
+/** Encryption master key prifix size */
+static const ulint ENCRYPTION_MASTER_KEY_PRIFIX_LEN = 9;
+
+/** Encryption master key prifix size */
+static const ulint ENCRYPTION_MASTER_KEY_NAME_MAX_LEN = 100;
+
+/** UUID of server instance, it's needed for composing master key name */
+static const ulint ENCRYPTION_SERVER_UUID_LEN = 36;
+
+/** Encryption information total size for 5.7.11: magic number + master_key_id +
+key + iv + checksum */
+static const ulint ENCRYPTION_INFO_SIZE_V1 = (ENCRYPTION_MAGIC_SIZE \
+ + (ENCRYPTION_KEY_LEN * 2) \
+ + 2 * sizeof(ulint));
+
+/** Encryption information total size: magic number + master_key_id +
+key + iv + server_uuid + checksum */
+static const ulint ENCRYPTION_INFO_SIZE_V2 = (ENCRYPTION_MAGIC_SIZE \
+ + (ENCRYPTION_KEY_LEN * 2) \
+ + ENCRYPTION_SERVER_UUID_LEN \
+ + 2 * sizeof(ulint));
+
+class IORequest;
+
+/** Encryption algorithm. */
+struct Encryption {
+
+ /** Algorithm types supported */
+ enum Type {
+
+ /** No encryption */
+ NONE = 0,
+
+ /** Use AES */
+ AES = 1,
+ };
+
+ /** Encryption information format version */
+ enum Version {
+
+ /** Version in 5.7.11 */
+ ENCRYPTION_VERSION_1 = 0,
+
+ /** Version in > 5.7.11 */
+ ENCRYPTION_VERSION_2 = 1,
+ };
+
+ /** Default constructor */
+ Encryption() : m_type(NONE) { };
+
+ /** Specific constructor
+ @param[in] type Algorithm type */
+ explicit Encryption(Type type)
+ :
+ m_type(type)
+ {
+#ifdef UNIV_DEBUG
+ switch (m_type) {
+ case NONE:
+ case AES:
+
+ default:
+ ut_error;
+ }
+#endif /* UNIV_DEBUG */
+ }
+
+ /** Copy constructor */
+ Encryption(const Encryption& other)
+ :
+ m_type(other.m_type),
+ m_key(other.m_key),
+ m_klen(other.m_klen),
+ m_iv(other.m_iv)
+ { };
+
+ /** Check if page is encrypted page or not
+ @param[in] page page which need to check
+ @return true if it is a encrypted page */
+ static bool is_encrypted_page(const byte* page)
+ MY_ATTRIBUTE((warn_unused_result));
+
+ /** Check the encryption option and set it
+ @param[in] option encryption option
+ @param[in/out] encryption The encryption type
+ @return DB_SUCCESS or DB_UNSUPPORTED */
+ dberr_t set_algorithm(const char* option, Encryption* type)
+ MY_ATTRIBUTE((warn_unused_result));
+
+ /** Validate the algorithm string.
+ @param[in] algorithm Encryption algorithm to check
+ @return DB_SUCCESS or error code */
+ static dberr_t validate(const char* algorithm)
+ MY_ATTRIBUTE((warn_unused_result));
+
+ /** Convert to a "string".
+ @param[in] type The encryption type
+ @return the string representation */
+ static const char* to_string(Type type)
+ MY_ATTRIBUTE((warn_unused_result));
+
+ /** Check if the string is "empty" or "none".
+ @param[in] algorithm Encryption algorithm to check
+ @return true if no algorithm requested */
+ static bool is_none(const char* algorithm)
+ MY_ATTRIBUTE((warn_unused_result));
+
+ /** Generate random encryption value for key and iv.
+ @param[in,out] value Encryption value */
+ static void random_value(byte* value);
+
+ /** Create new master key for key rotation.
+ @param[in,out] master_key master key */
+ static void create_master_key(byte** master_key);
+
+ /** Get master key by key id.
+ @param[in] master_key_id master key id
+ @param[in] srv_uuid uuid of server instance
+ @param[in,out] master_key master key */
+ static void get_master_key(ulint master_key_id,
+ char* srv_uuid,
+ byte** master_key);
+
+ /** Get current master key and key id.
+ @param[in,out] master_key_id master key id
+ @param[in,out] master_key master key
+ @param[in,out] version encryption information version */
+ static void get_master_key(ulint* master_key_id,
+ byte** master_key,
+ Encryption::Version* version);
+
+ /** Encrypt the page data contents. Page type can't be
+ FIL_PAGE_ENCRYPTED, FIL_PAGE_COMPRESSED_AND_ENCRYPTED,
+ FIL_PAGE_ENCRYPTED_RTREE.
+ @param[in] type IORequest
+ @param[in,out] src page data which need to encrypt
+ @param[in] src_len Size of the source in bytes
+ @param[in,out] dst destination area
+ @param[in,out] dst_len Size of the destination in bytes
+ @return buffer data, dst_len will have the length of the data */
+ byte* encrypt(
+ const IORequest& type,
+ byte* src,
+ ulint src_len,
+ byte* dst,
+ ulint* dst_len)
+ MY_ATTRIBUTE((warn_unused_result));
+
+ /** Decrypt the page data contents. Page type must be
+ FIL_PAGE_ENCRYPTED, FIL_PAGE_COMPRESSED_AND_ENCRYPTED,
+ FIL_PAGE_ENCRYPTED_RTREE, if not then the source contents are
+ left unchanged and DB_SUCCESS is returned.
+ @param[in] type IORequest
+ @param[in,out] src Data read from disk, decrypt
+ data will be copied to this page
+ @param[in] src_len source data length
+ @param[in,out] dst Scratch area to use for decrypt
+ @param[in] dst_len Size of the scratch area in bytes
+ @return DB_SUCCESS or error code */
+ dberr_t decrypt(
+ const IORequest& type,
+ byte* src,
+ ulint src_len,
+ byte* dst,
+ ulint dst_len)
+ MY_ATTRIBUTE((warn_unused_result));
+
+ /** Encrypt type */
+ Type m_type;
+
+ /** Encrypt key */
+ byte* m_key;
+
+ /** Encrypt key length*/
+ ulint m_klen;
+
+ /** Encrypt initial vector */
+ byte* m_iv;
+
+ /** Current master key id */
+ static ulint master_key_id;
+
+ /** Current uuid of server instance */
+ static char uuid[ENCRYPTION_SERVER_UUID_LEN + 1];
+};
+
/** Types for AIO operations @{ */
/** No transformations during read/write, write as is. */
@@ -379,42 +584,42 @@ public:
/** @return true if ignore missing flag is set */
static bool ignore_missing(ulint type)
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((type & IGNORE_MISSING) == IGNORE_MISSING);
}
/** @return true if it is a read request */
bool is_read() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & READ) == READ);
}
/** @return true if it is a write request */
bool is_write() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & WRITE) == WRITE);
}
/** @return true if it is a redo log write */
bool is_log() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & LOG) == LOG);
}
/** @return true if the simulated AIO thread should be woken up */
bool is_wake() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & DO_NOT_WAKE) == 0);
}
/** @return true if partial read warning disabled */
bool is_partial_io_warning_disabled() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & DISABLE_PARTIAL_IO_WARNINGS)
== DISABLE_PARTIAL_IO_WARNINGS);
@@ -428,21 +633,21 @@ public:
/** @return true if missing files should be ignored */
bool ignore_missing() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(ignore_missing(m_type));
}
/** @return true if punch hole should be used */
bool punch_hole() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & PUNCH_HOLE) == PUNCH_HOLE);
}
/** @return true if the read should be validated */
bool validate() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_a(is_read() ^ is_write());
@@ -471,7 +676,7 @@ public:
/** @return the block size to use for IO */
ulint block_size() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_block_size);
}
@@ -514,21 +719,21 @@ public:
/** Get the compression algorithm.
@return the compression algorithm */
Compression compression_algorithm() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_compression);
}
/** @return true if the page should be compressed */
bool is_compressed() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(compression_algorithm().m_type != Compression::NONE);
}
/** @return true if the page read should not be transformed. */
bool is_compression_enabled() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & NO_COMPRESSION) == 0);
}
@@ -539,6 +744,54 @@ public:
m_type |= NO_COMPRESSION;
}
+ /** Set encryption algorithm
+ @param[in] type The encryption algorithm to use */
+ void encryption_algorithm(Encryption::Type type)
+ {
+ if (type == Encryption::NONE) {
+ return;
+ }
+
+ m_encryption.m_type = type;
+ }
+
+ /** Set encryption key and iv
+ @param[in] key The encryption key to use
+ @param[in] key_len length of the encryption key
+ @param[in] iv The encryption iv to use */
+ void encryption_key(byte* key,
+ ulint key_len,
+ byte* iv)
+ {
+ m_encryption.m_key = key;
+ m_encryption.m_klen = key_len;
+ m_encryption.m_iv = iv;
+ }
+
+ /** Get the encryption algorithm.
+ @return the encryption algorithm */
+ Encryption encryption_algorithm() const
+ MY_ATTRIBUTE((warn_unused_result))
+ {
+ return(m_encryption);
+ }
+
+ /** @return true if the page should be encrypted. */
+ bool is_encrypted() const
+ MY_ATTRIBUTE((warn_unused_result))
+ {
+ return(m_encryption.m_type != Encryption::NONE);
+ }
+
+ /** Clear all encryption related flags */
+ void clear_encrypted()
+ {
+ m_encryption.m_key = NULL;
+ m_encryption.m_klen = 0;
+ m_encryption.m_iv = NULL;
+ m_encryption.m_type = Encryption::NONE;
+ }
+
/** Note that the IO is for double write recovery. */
void dblwr_recover()
{
@@ -547,7 +800,7 @@ public:
/** @return true if the request is from the dblwr recovery */
bool is_dblwr_recover() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return((m_type & DBLWR_RECOVER) == DBLWR_RECOVER);
}
@@ -555,6 +808,14 @@ public:
/** @return true if punch hole is supported */
static bool is_punch_hole_supported()
{
+
+ /* In this debugging mode, we act as if punch hole is supported,
+ and then skip any calls to actually punch a hole here.
+ In this way, Transparent Page Compression is still being tested. */
+ DBUG_EXECUTE_IF("ignore_punch_hole",
+ return(true);
+ );
+
#if defined(HAVE_FALLOC_PUNCH_HOLE_AND_KEEP_SIZE) || defined(_WIN32)
return(true);
#else
@@ -571,6 +832,9 @@ private:
/** Compression algorithm */
Compression m_compression;
+
+ /** Encryption algorithm */
+ Encryption m_encryption;
};
/* @} */
@@ -626,13 +890,13 @@ enum os_file_type_t {
of this size from the thread stack; that is why this should not be made much
bigger than 4000 bytes. The maximum path length used by any storage engine
in the server must be at least this big. */
-#define OS_FILE_MAX_PATH 4000
/* MySQL 5.7 my_global.h */
#ifndef FN_REFLEN_SE
#define FN_REFLEN_SE 4000
#endif
+#define OS_FILE_MAX_PATH 4000
#if (FN_REFLEN_SE < OS_FILE_MAX_PATH)
# error "(FN_REFLEN_SE < OS_FILE_MAX_PATH)"
#endif
@@ -661,10 +925,9 @@ is null then it will create the file in the mysql server configuration
parameter (--tmpdir).
@param[in] path location for creating temporary file
@return temporary file handle, or NULL on error */
-UNIV_INTERN
FILE*
-os_file_create_tmpfile();
-
+os_file_create_tmpfile(
+ const char* path);
#endif /* !UNIV_HOTBACKUP */
/** The os_file_opendir() function opens a directory stream corresponding to the
@@ -757,7 +1020,7 @@ os_file_create_simple_no_error_handling_func(
ulint access_type,
bool read_only,
bool* success)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Tries to disable OS caching on an opened file descriptor.
@param[in] fd file descriptor to alter
@@ -796,7 +1059,7 @@ os_file_create_func(
ulint type,
bool read_only,
bool* success)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Deletes a file. The file has to be closed before calling this.
@param[in] name file path as a null-terminated string
@@ -991,7 +1254,7 @@ pfs_os_file_create_simple_func(
bool* success,
const char* src_file,
ulint src_line)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Please use the corresponding macro
os_file_create_simple_no_error_handling(), not directly this function!
@@ -1022,7 +1285,7 @@ pfs_os_file_create_simple_no_error_handling_func(
bool* success,
const char* src_file,
ulint src_line)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Please use the corresponding macro os_file_create(), not directly
this function!
@@ -1051,12 +1314,12 @@ pfs_os_file_create_func(
const char* name,
ulint create_mode,
ulint purpose,
- ulint access_type,
+ ulint type,
bool read_only,
bool* success,
const char* src_file,
ulint src_line)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Please use the corresponding macro os_file_close(), not directly
this function!
@@ -1266,7 +1529,7 @@ to original un-instrumented file I/O APIs */
# define os_file_create(key, name, create, purpose, type, read_only, \
success) \
os_file_create_func(name, create, purpose, type, read_only, \
- success)
+ success)
# define os_file_create_simple(key, name, create_mode, access, \
read_only, success) \
@@ -1321,7 +1584,7 @@ os_file_close_no_error_handling(os_file_t file);
os_file_size_t
os_file_get_size(
const char* filename)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Gets a file size.
@param[in] file handle to a file
@@ -1344,7 +1607,7 @@ os_file_set_size(
os_file_t file,
os_offset_t size,
bool read_only)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Truncates a file at its current position.
@param[in/out] file file to be truncated
@@ -1401,7 +1664,7 @@ os_file_read_func(
void* buf,
os_offset_t offset,
ulint n)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Rewind file to its start, read at most size - 1 bytes from it to str, and
NUL-terminate str. All errors are silently ignored. This function is
@@ -1434,7 +1697,7 @@ os_file_read_no_error_handling_func(
os_offset_t offset,
ulint n,
ulint* o)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** NOTE! Use the corresponding macro os_file_write(), not directly this
function!
@@ -1453,7 +1716,7 @@ os_file_write_func(
const void* buf,
os_offset_t offset,
ulint n)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Check the existence and type of the given file.
@param[in] path pathname of the file
@@ -1652,11 +1915,14 @@ os_file_get_status(
bool read_only);
#if !defined(UNIV_HOTBACKUP)
-/** Creates a temporary file that will be deleted on close.
+/** Creates a temporary file in the location specified by the parameter
+path. If the path is NULL then it will be created on --tmpdir location.
+This function is defined in ha_innodb.cc.
@param[in] path location for creating temporary file
@return temporary file descriptor, or < 0 on error */
int
-innobase_mysql_tmpfile();
+innobase_mysql_tmpfile(
+ const char* path);
#endif /* !UNIV_HOTBACKUP */
@@ -1689,7 +1955,7 @@ os_file_punch_hole(
os_file_t fh,
os_offset_t off,
os_offset_t len)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Check if the file system supports sparse files.
@@ -1706,7 +1972,7 @@ bool
os_is_sparse_file_supported(
const char* path,
os_file_t fh)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Decompress the page data contents. Page type must be FIL_PAGE_COMPRESSED, if
not then the source contents are left unchanged and DB_SUCCESS is returned.
@@ -1723,21 +1989,13 @@ os_file_decompress_page(
byte* src,
byte* dst,
ulint dst_len)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Normalizes a directory path for the current OS:
On Windows, we convert '/' to '\', else we convert '\' to '/'.
@param[in,out] str A null-terminated directory and file path */
void os_normalize_path(char* str);
-/** Normalizes a directory path for Windows: converts '/' to '\'.
-@param[in,out] str A null-terminated Windows directory and file path */
-#ifdef _WIN32
-#define os_normalize_path_for_win(str) os_normalize_path(str)
-#else
-#define os_normalize_path_for_win(str)
-#endif
-
/* Determine if a path is an absolute path or not.
@param[in] OS directory or file path to evaluate
@retval true if an absolute path
diff --git a/storage/innobase/include/os0file.ic b/storage/innobase/include/os0file.ic
index ec90548dd64..74d0b2c83a8 100644
--- a/storage/innobase/include/os0file.ic
+++ b/storage/innobase/include/os0file.ic
@@ -219,6 +219,11 @@ an asynchronous i/o operation.
@param[in,out] m2 message for the AIO handler (can be used to
identify a completed AIO operation); ignored
if mode is OS_AIO_SYNC
+@param[in,out] write_size Actual write size initialized
+ after fist successfull trim
+ operation for this page and if
+ initialized we do not trim again if
+ actual page size
@param[in] src_file file name where func invoked
@param[in] src_line line where the func invoked
@return DB_SUCCESS if request was queued successfully, FALSE if fail */
@@ -235,11 +240,7 @@ pfs_os_aio_func(
bool read_only,
fil_node_t* m1,
void* m2,
- ulint* write_size,/*!< in/out: Actual write size initialized
- after fist successfull trim
- operation for this page and if
- initialized we do not trim again if
- actual page size does not decrease. */
+ ulint* write_size,
const char* src_file,
ulint src_line)
{
diff --git a/storage/innobase/include/os0thread.h b/storage/innobase/include/os0thread.h
index 32fd1c785c0..0be2fa89d06 100644
--- a/storage/innobase/include/os0thread.h
+++ b/storage/innobase/include/os0thread.h
@@ -117,14 +117,11 @@ os_thread_create_func(
os_thread_id_t* thread_id); /*!< out: id of the created
thread, or NULL */
-/*****************************************************************//**
-Exits the current thread. */
+/** Exits the current thread. */
void
-os_thread_exit(
-/*===========*/
- void* exit_value) /*!< in: exit value; in Windows this void*
- is cast as a DWORD */
+os_thread_exit()
UNIV_COLD MY_ATTRIBUTE((noreturn));
+
/*****************************************************************//**
Returns the thread identifier of current thread.
@return current thread identifier */
diff --git a/storage/innobase/include/page0cur.h b/storage/innobase/include/page0cur.h
index 58be8b0aa2e..c111717d868 100644
--- a/storage/innobase/include/page0cur.h
+++ b/storage/innobase/include/page0cur.h
@@ -159,9 +159,10 @@ page_cur_tuple_insert(
mem_heap_t** heap, /*!< in/out: pointer to memory heap, or NULL */
ulint n_ext, /*!< in: number of externally stored columns */
mtr_t* mtr, /*!< in: mini-transaction handle, or NULL */
- bool use_cache = false);
+ bool use_cache = false)
/*!< in: if true, then use record cache to
hold the tuple converted record. */
+ MY_ATTRIBUTE((nonnull(1,2,3,4,5), warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
/***********************************************************//**
Inserts a record next to page cursor. Returns pointer to inserted record if
diff --git a/storage/innobase/include/page0page.h b/storage/innobase/include/page0page.h
index 8d1e5b17542..3bb622127fb 100644
--- a/storage/innobase/include/page0page.h
+++ b/storage/innobase/include/page0page.h
@@ -264,7 +264,7 @@ page_header_get_offs(
/*=================*/
const page_t* page, /*!< in: page */
ulint field) /*!< in: PAGE_FREE, ... */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/*************************************************************//**
Returns the pointer stored in the given header field, or NULL. */
@@ -530,7 +530,7 @@ bool
page_is_leaf(
/*=========*/
const page_t* page) /*!< in: page */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
Determine whether the page is empty.
@return true if the page is empty (PAGE_N_RECS = 0) */
@@ -539,7 +539,7 @@ bool
page_is_empty(
/*==========*/
const page_t* page) /*!< in: page */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/** Determine whether a page is an index root page.
@param[in] page page frame
@return true if the page is a root page of an index */
@@ -547,7 +547,7 @@ UNIV_INLINE
bool
page_is_root(
const page_t* page)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
Determine whether the page contains garbage.
@return true if the page contains garbage (PAGE_GARBAGE is not 0) */
@@ -556,7 +556,7 @@ bool
page_has_garbage(
/*=============*/
const page_t* page) /*!< in: page */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
Gets the pointer to the next record on the page.
@return pointer to next record */
@@ -656,7 +656,7 @@ ibool
page_rec_is_user_rec(
/*=================*/
const rec_t* rec) /*!< in: record */
- MY_ATTRIBUTE((const));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
TRUE if the record is the supremum record on a page.
@return TRUE if the supremum record */
@@ -665,7 +665,7 @@ ibool
page_rec_is_supremum(
/*=================*/
const rec_t* rec) /*!< in: record */
- MY_ATTRIBUTE((const));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
TRUE if the record is the infimum record on a page.
@@ -675,7 +675,7 @@ ibool
page_rec_is_infimum(
/*================*/
const rec_t* rec) /*!< in: record */
- MY_ATTRIBUTE((const));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
true if the record is the first user record on a page.
@@ -686,7 +686,7 @@ page_rec_is_first(
/*==============*/
const rec_t* rec, /*!< in: record */
const page_t* page) /*!< in: page */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
true if the record is the second user record on a page.
@@ -697,7 +697,7 @@ page_rec_is_second(
/*===============*/
const rec_t* rec, /*!< in: record */
const page_t* page) /*!< in: page */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
true if the record is the last user record on a page.
@@ -708,7 +708,7 @@ page_rec_is_last(
/*=============*/
const rec_t* rec, /*!< in: record */
const page_t* page) /*!< in: page */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
true if the record is the second last user record on a page.
@@ -719,7 +719,7 @@ page_rec_is_second_last(
/*====================*/
const rec_t* rec, /*!< in: record */
const page_t* page) /*!< in: page */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/***************************************************************//**
Looks for the record which owns the given record.
diff --git a/storage/innobase/include/page0types.h b/storage/innobase/include/page0types.h
index 5dabcf2e67d..fe56468c454 100644
--- a/storage/innobase/include/page0types.h
+++ b/storage/innobase/include/page0types.h
@@ -75,13 +75,14 @@ enum page_cur_mode_t {
which extend it */
/* These search mode is for search R-tree index. */
- PAGE_CUR_CONTAIN = 7,
- PAGE_CUR_INTERSECT = 8,
- PAGE_CUR_WITHIN = 9,
- PAGE_CUR_DISJOINT = 10,
- PAGE_CUR_MBR_EQUAL = 11,
- PAGE_CUR_RTREE_INSERT = 12,
- PAGE_CUR_RTREE_LOCATE = 13
+ PAGE_CUR_CONTAIN = 7,
+ PAGE_CUR_INTERSECT = 8,
+ PAGE_CUR_WITHIN = 9,
+ PAGE_CUR_DISJOINT = 10,
+ PAGE_CUR_MBR_EQUAL = 11,
+ PAGE_CUR_RTREE_INSERT = 12,
+ PAGE_CUR_RTREE_LOCATE = 13,
+ PAGE_CUR_RTREE_GET_FATHER = 14
};
diff --git a/storage/innobase/include/page0zip.h b/storage/innobase/include/page0zip.h
index 20643b60bfa..7b5df3d306b 100644
--- a/storage/innobase/include/page0zip.h
+++ b/storage/innobase/include/page0zip.h
@@ -2,7 +2,6 @@
Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
-Copyright (c) 2013, 2016, MariaDB Corporation
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
@@ -88,7 +87,7 @@ ulint
page_zip_get_size(
/*==============*/
const page_zip_des_t* page_zip) /*!< in: compressed page */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Set the size of a compressed page in bytes. */
UNIV_INLINE
@@ -113,7 +112,7 @@ page_zip_rec_needs_ext(
ulint comp,
ulint n_fields,
const page_size_t& page_size)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Determine the guaranteed free space on an empty page.
@@ -124,6 +123,15 @@ page_zip_empty_size(
ulint n_fields, /*!< in: number of columns in the index */
ulint zip_size) /*!< in: compressed page size in bytes */
MY_ATTRIBUTE((const));
+
+/** Check whether a tuple is too big for compressed table
+@param[in] index dict index object
+@param[in] entry entry for the index
+@return true if it's too big, otherwise false */
+bool
+page_zip_is_too_big(
+ const dict_index_t* index,
+ const dtuple_t* entry);
#endif /* !UNIV_HOTBACKUP */
/**********************************************************************//**
@@ -243,7 +251,7 @@ page_zip_max_ins_size(
/*==================*/
const page_zip_des_t* page_zip,/*!< in: compressed page */
ibool is_clust)/*!< in: TRUE if clustered index */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Determine if enough space is available in the modification log.
@@ -257,7 +265,7 @@ page_zip_available(
ulint length, /*!< in: combined size of the record */
ulint create) /*!< in: nonzero=add the record to
the heap */
- MY_ATTRIBUTE((nonnull, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Write data to the uncompressed header portion of a page. The data must
@@ -553,26 +561,6 @@ void
page_zip_reset_stat_per_index();
/*===========================*/
-#ifndef UNIV_HOTBACKUP
-/** Check if a pointer to an uncompressed page matches a compressed page.
-When we IMPORT a tablespace the blocks and accompanying frames are allocted
-from outside the buffer pool.
-@param ptr pointer to an uncompressed page frame
-@param page_zip compressed page descriptor
-@return TRUE if ptr and page_zip refer to the same block */
-# define PAGE_ZIP_MATCH(ptr, page_zip) \
- (((page_zip)->m_external \
- && (page_align(ptr) + UNIV_PAGE_SIZE == (page_zip)->data)) \
- || buf_frame_get_page_zip(ptr) == (page_zip))
-#else /* !UNIV_HOTBACKUP */
-/** Check if a pointer to an uncompressed page matches a compressed page.
-@param ptr pointer to an uncompressed page frame
-@param page_zip compressed page descriptor
-@return TRUE if ptr and page_zip refer to the same block */
-# define PAGE_ZIP_MATCH(ptr, page_zip) \
- (page_align(ptr) + UNIV_PAGE_SIZE == (page_zip)->data)
-#endif /* !UNIV_HOTBACKUP */
-
#ifdef UNIV_MATERIALIZE
# undef UNIV_INLINE
# define UNIV_INLINE UNIV_INLINE_ORIGINAL
@@ -581,20 +569,6 @@ from outside the buffer pool.
#ifndef UNIV_NONINL
# include "page0zip.ic"
#endif
-
-/** Issue a warning when the checksum that is stored in the page is valid,
-but different than the global setting innodb_checksum_algorithm.
-@param[in] current_algo current checksum algorithm
-@param[in] page_checksum page valid checksum
-@param[in] space_id tablespace id
-@param[in] page_no page number */
-void
-page_warn_strict_checksum(
- srv_checksum_algorithm_t curr_algo,
- srv_checksum_algorithm_t page_checksum,
- ulint space_id,
- ulint page_no);
-
#endif /* !UNIV_INNOCHECKSUM */
#endif /* page0zip_h */
diff --git a/storage/innobase/include/page0zip.ic b/storage/innobase/include/page0zip.ic
index cbb3660a6ae..9963fe01c82 100644
--- a/storage/innobase/include/page0zip.ic
+++ b/storage/innobase/include/page0zip.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2005, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2005, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
This program is free software; you can redistribute it and/or modify it under
@@ -351,7 +351,6 @@ page_zip_write_header(
{
ulint pos;
- ut_ad(PAGE_ZIP_MATCH(str, page_zip));
ut_ad(page_zip_simple_validate(page_zip));
UNIV_MEM_ASSERT_RW(page_zip->data, page_zip_get_size(page_zip));
diff --git a/storage/innobase/include/pars0pars.h b/storage/innobase/include/pars0pars.h
index f52b35c1918..7e153d0c19b 100644
--- a/storage/innobase/include/pars0pars.h
+++ b/storage/innobase/include/pars0pars.h
@@ -33,6 +33,7 @@ Created 11/19/1996 Heikki Tuuri
#include "row0types.h"
#include "trx0types.h"
#include "ut0vec.h"
+#include "row0mysql.h"
/** Type of the user functions. The first argument is always InnoDB-supplied
and varies in type, while 'user_arg' is a user-supplied argument. The
@@ -418,18 +419,21 @@ que_fork_t*
pars_stored_procedure_call(
/*=======================*/
sym_node_t* sym_node); /*!< in: stored procedure name */
-/******************************************************************//**
-Completes a query graph by adding query thread and fork nodes
+/** Completes a query graph by adding query thread and fork nodes
above it and prepares the graph for running. The fork created is of
type QUE_FORK_MYSQL_INTERFACE.
+@param[in] node root node for an incomplete query
+ graph, or NULL for dummy graph
+@param[in] trx transaction handle
+@param[in] heap memory heap from which allocated
+@param[in] prebuilt row prebuilt structure
@return query thread node to run */
que_thr_t*
pars_complete_graph_for_exec(
-/*=========================*/
- que_node_t* node, /*!< in: root node for an incomplete
- query graph, or NULL for dummy graph */
- trx_t* trx, /*!< in: transaction handle */
- mem_heap_t* heap) /*!< in: memory heap from which allocated */
+ que_node_t* node,
+ trx_t* trx,
+ mem_heap_t* heap,
+ row_prebuilt_t* prebuilt)
MY_ATTRIBUTE((nonnull(2,3), warn_unused_result));
/****************************************************************//**
diff --git a/storage/innobase/include/que0que.h b/storage/innobase/include/que0que.h
index 68a1115ae97..3e90e0b25e3 100644
--- a/storage/innobase/include/que0que.h
+++ b/storage/innobase/include/que0que.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -74,14 +74,16 @@ que_node_set_parent(
/*================*/
que_node_t* node, /*!< in: graph node */
que_node_t* parent);/*!< in: parent */
-/***********************************************************************//**
-Creates a query graph thread node.
+/** Creates a query graph thread node.
+@param[in] parent parent node, i.e., a fork node
+@param[in] heap memory heap where created
+@param[in] prebuilt row prebuilt structure
@return own: query thread node */
que_thr_t*
que_thr_create(
-/*===========*/
- que_fork_t* parent, /*!< in: parent node, i.e., a fork node */
- mem_heap_t* heap); /*!< in: memory heap where created */
+ que_fork_t* parent,
+ mem_heap_t* heap,
+ row_prebuilt_t* prebuilt);
/**********************************************************************//**
Frees a query graph, but not the heap where it was created. Does not free
explicit cursor declarations, they are freed in que_graph_free. */
@@ -398,6 +400,8 @@ struct que_thr_t{
ulint fk_cascade_depth; /*!< maximum cascading call depth
supported for foreign key constraint
related delete/updates */
+ row_prebuilt_t* prebuilt; /*!< prebuilt structure processed by
+ the query thread */
};
#define QUE_THR_MAGIC_N 8476583
diff --git a/storage/innobase/include/read0read.h b/storage/innobase/include/read0read.h
index 9ba6acf65aa..129341be77c 100644
--- a/storage/innobase/include/read0read.h
+++ b/storage/innobase/include/read0read.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2013, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/include/read0types.h b/storage/innobase/include/read0types.h
index 230aac49ec0..c83c7e04f11 100644
--- a/storage/innobase/include/read0types.h
+++ b/storage/innobase/include/read0types.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -161,7 +161,7 @@ public:
bool changes_visible(
trx_id_t id,
const table_name_t& name) const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(id > 0);
diff --git a/storage/innobase/include/rem0cmp.h b/storage/innobase/include/rem0cmp.h
index 4016900ff7f..a59479849a8 100644
--- a/storage/innobase/include/rem0cmp.h
+++ b/storage/innobase/include/rem0cmp.h
@@ -62,7 +62,7 @@ cmp_data_data(
ulint len1,
const byte* data2,
ulint len2)
- __attribute__((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Compare two data fields.
@param[in] dfield1 data field; must have type field set
@@ -92,7 +92,22 @@ cmp_dtuple_rec_with_gis(
const rec_t* rec,
const ulint* offsets,
page_cur_mode_t mode)
- __attribute__((nonnull));
+ MY_ATTRIBUTE((nonnull));
+
+/** Compare a GIS data tuple to a physical record in rtree non-leaf node.
+We need to check the page number field, since we don't store pk field in
+rtree non-leaf node.
+@param[in] dtuple data tuple
+@param[in] rec R-tree record
+@param[in] offsets rec_get_offsets(rec)
+@param[in] mode compare mode
+@retval negative if dtuple is less than rec */
+int
+cmp_dtuple_rec_with_gis_internal(
+ const dtuple_t* dtuple,
+ const rec_t* rec,
+ const ulint* offsets);
+
/** Compare a data tuple to a physical record.
@param[in] dtuple data tuple
@param[in] rec B-tree record
@@ -134,7 +149,7 @@ cmp_dtuple_rec_with_match_bytes(
const ulint* offsets,
ulint* matched_fields,
ulint* matched_bytes)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Compare a data tuple to a physical record.
@see cmp_dtuple_rec_with_match
@param[in] dtuple data tuple
diff --git a/storage/innobase/include/rem0rec.h b/storage/innobase/include/rem0rec.h
index 0edb73ebfee..8490e7c9c88 100644
--- a/storage/innobase/include/rem0rec.h
+++ b/storage/innobase/include/rem0rec.h
@@ -101,7 +101,7 @@ rec_get_next_ptr_const(
/*===================*/
const rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to get the pointer of the next chained record
on the same page.
@@ -112,7 +112,7 @@ rec_get_next_ptr(
/*=============*/
rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to get the offset of the
next chained record on the same page.
@@ -123,7 +123,7 @@ rec_get_next_offs(
/*==============*/
const rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the next record offset field
of an old-style record. */
@@ -153,7 +153,7 @@ ulint
rec_get_n_fields_old(
/*=================*/
const rec_t* rec) /*!< in: physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to get the number of fields
in a record.
@@ -164,7 +164,7 @@ rec_get_n_fields(
/*=============*/
const rec_t* rec, /*!< in: physical record */
const dict_index_t* index) /*!< in: record descriptor */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Confirms the n_fields of the entry is sane with comparing the other
record in the same page specified
@@ -178,7 +178,7 @@ rec_n_fields_is_sane(
dict_index_t* index,
const rec_t* rec,
const dtuple_t* entry)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to get the number of records owned by the
@@ -189,7 +189,7 @@ ulint
rec_get_n_owned_old(
/*================*/
const rec_t* rec) /*!< in: old-style physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the number of owned records. */
UNIV_INLINE
@@ -208,7 +208,7 @@ ulint
rec_get_n_owned_new(
/*================*/
const rec_t* rec) /*!< in: new-style physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the number of owned records. */
UNIV_INLINE
@@ -229,7 +229,7 @@ rec_get_info_bits(
/*==============*/
const rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the info bits of a record. */
UNIV_INLINE
@@ -256,7 +256,7 @@ ulint
rec_get_status(
/*===========*/
const rec_t* rec) /*!< in: physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the status bits of a new-style record. */
@@ -278,7 +278,7 @@ rec_get_info_and_status_bits(
/*=========================*/
const rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the info and status
bits of a record. (Only compact records have status bits.) */
@@ -299,7 +299,7 @@ rec_get_deleted_flag(
/*=================*/
const rec_t* rec, /*!< in: physical record */
ulint comp) /*!< in: nonzero=compact page format */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the deleted bit. */
UNIV_INLINE
@@ -327,7 +327,7 @@ ibool
rec_get_node_ptr_flag(
/*==================*/
const rec_t* rec) /*!< in: physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to get the order number
of an old-style record in the heap of the index page.
@@ -337,7 +337,7 @@ ulint
rec_get_heap_no_old(
/*================*/
const rec_t* rec) /*!< in: physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the heap number
field in an old-style record. */
@@ -357,7 +357,7 @@ ulint
rec_get_heap_no_new(
/*================*/
const rec_t* rec) /*!< in: physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the heap number
field in a new-style record. */
@@ -377,7 +377,7 @@ ibool
rec_get_1byte_offs_flag(
/*====================*/
const rec_t* rec) /*!< in: physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
The following function is used to set the 1-byte offsets flag. */
@@ -400,7 +400,7 @@ rec_1_get_field_end_info(
/*=====================*/
const rec_t* rec, /*!< in: record */
ulint n) /*!< in: field index */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Returns the offset of nth field end if the record is stored in the 2-byte
@@ -414,7 +414,7 @@ rec_2_get_field_end_info(
/*=====================*/
const rec_t* rec, /*!< in: record */
ulint n) /*!< in: field index */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Returns nonzero if the field is stored off-page.
@@ -426,7 +426,7 @@ rec_2_is_field_extern(
/*==================*/
const rec_t* rec, /*!< in: record */
ulint n) /*!< in: field index */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Determine how many of the first n columns in a compact
@@ -545,7 +545,7 @@ rec_get_nth_field_size(
/*===================*/
const rec_t* rec, /*!< in: record */
ulint n) /*!< in: index of the field */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/************************************************************//**
The following function is used to get an offset to the nth
data field in a record.
@@ -570,7 +570,7 @@ ulint
rec_offs_comp(
/*==========*/
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Determine if the offsets are for a record containing
externally stored columns.
@@ -580,7 +580,7 @@ ulint
rec_offs_any_extern(
/*================*/
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Determine if the offsets are for a record containing null BLOB pointers.
@return first field containing a null BLOB pointer, or NULL if none found */
@@ -590,7 +590,7 @@ rec_offs_any_null_extern(
/*=====================*/
const rec_t* rec, /*!< in: record */
const ulint* offsets) /*!< in: rec_get_offsets(rec) */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Returns nonzero if the extern bit is set in nth field of rec.
@return nonzero if externally stored */
@@ -600,7 +600,7 @@ rec_offs_nth_extern(
/*================*/
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
ulint n) /*!< in: nth field */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Mark the nth field as externally stored.
@param[in] offsets array returned by rec_get_offsets()
@@ -618,7 +618,7 @@ rec_offs_nth_sql_null(
/*==================*/
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
ulint n) /*!< in: nth field */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Gets the physical size of a field.
@return length of field */
@@ -628,7 +628,7 @@ rec_offs_nth_size(
/*==============*/
const ulint* offsets,/*!< in: array returned by rec_get_offsets() */
ulint n) /*!< in: nth field */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Returns the number of extern bits set in a record.
@@ -638,7 +638,7 @@ ulint
rec_offs_n_extern(
/*==============*/
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/***********************************************************//**
This is used to modify the value of an already existing field in a record.
The previous value must have exactly the same size as the new value. If len
@@ -670,7 +670,7 @@ ulint
rec_get_data_size_old(
/*==================*/
const rec_t* rec) /*!< in: physical record */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************//**
The following function returns the number of allocated elements
for an array of offsets.
@@ -680,7 +680,7 @@ ulint
rec_offs_get_n_alloc(
/*=================*/
const ulint* offsets)/*!< in: array for rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************//**
The following function sets the number of allocated elements
for an array of offsets. */
@@ -702,7 +702,7 @@ ulint
rec_offs_n_fields(
/*==============*/
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************//**
The following function returns the data size of a physical
record, that is the sum of field lengths. SQL null fields
@@ -714,7 +714,7 @@ ulint
rec_offs_data_size(
/*===============*/
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************//**
Returns the total size of record minus data size of record.
The value returned by the function is the distance from record
@@ -725,7 +725,7 @@ ulint
rec_offs_extra_size(
/*================*/
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************//**
Returns the total size of a physical record.
@return size */
@@ -734,7 +734,7 @@ ulint
rec_offs_size(
/*==========*/
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifdef UNIV_DEBUG
/**********************************************************//**
Returns a pointer to the start of the record.
@@ -745,7 +745,7 @@ rec_get_start(
/*==========*/
const rec_t* rec, /*!< in: pointer to record */
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************//**
Returns a pointer to the end of the record.
@return pointer to end */
@@ -755,7 +755,7 @@ rec_get_end(
/*========*/
const rec_t* rec, /*!< in: pointer to record */
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#else /* UNIV_DEBUG */
# define rec_get_start(rec, offsets) ((rec) - rec_offs_extra_size(offsets))
# define rec_get_end(rec, offsets) ((rec) + rec_offs_data_size(offsets))
@@ -786,7 +786,7 @@ rec_get_converted_size_temp(
const dtuple_t* v_entry,/*!< in: dtuple contains virtual column
data */
ulint* extra) /*!< out: extra size */
- MY_ATTRIBUTE((warn_unused_result, nonnull(1)));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Determine the offset to each field in temporary file.
@@ -845,7 +845,7 @@ rec_fold(
ulint n_fields,
ulint n_bytes,
index_id_t tree_id)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
/*********************************************************//**
Builds a physical record out of a data tuple and
@@ -860,7 +860,7 @@ rec_convert_dtuple_to_rec(
const dtuple_t* dtuple, /*!< in: data tuple */
ulint n_ext) /*!< in: number of
externally stored columns */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************//**
Returns the extra size of an old-style physical record if we know its
data size and number of fields.
@@ -898,7 +898,7 @@ rec_get_converted_size_comp(
const dfield_t* fields, /*!< in: array of data fields */
ulint n_fields,/*!< in: number of data fields */
ulint* extra) /*!< out: extra size */
- MY_ATTRIBUTE((nonnull(1)));
+ MY_ATTRIBUTE((nonnull(1,3)));
/**********************************************************//**
The following function returns the size of a data tuple when converted to
a physical record.
@@ -962,7 +962,7 @@ rec_print_mbr_rec(
FILE* file, /*!< in: file where to print */
const rec_t* rec, /*!< in: physical record */
const ulint* offsets)/*!< in: array returned by rec_get_offsets() */
- __attribute__((nonnull));
+ MY_ATTRIBUTE((nonnull));
/***************************************************************//**
Prints a physical record. */
void
@@ -1124,6 +1124,7 @@ int wsrep_rec_get_foreign_key(
dict_index_t* index_ref, /* in: index for referenced table */
ibool new_protocol); /* in: protocol > 1 */
#endif /* WITH_WSREP */
+
#ifndef UNIV_NONINL
#include "rem0rec.ic"
#endif
diff --git a/storage/innobase/include/rem0rec.ic b/storage/innobase/include/rem0rec.ic
index 4d2cbcb4944..b855a39da9e 100644
--- a/storage/innobase/include/rem0rec.ic
+++ b/storage/innobase/include/rem0rec.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/include/row0ftsort.h b/storage/innobase/include/row0ftsort.h
index c06327c243e..7e39fe33d9f 100644
--- a/storage/innobase/include/row0ftsort.h
+++ b/storage/innobase/include/row0ftsort.h
@@ -94,7 +94,7 @@ struct fts_psort_t {
ulint state; /*!< parent thread state */
fts_doc_list_t fts_doc_list; /*!< doc list to process */
fts_psort_common_t* psort_common; /*!< ptr to all psort info */
- os_thread_id_t thread_hdl; /*!< thread handler */
+ os_thread_t thread_hdl; /*!< thread handler */
dberr_t error; /*!< db error during psort */
ulint memory_used; /*!< memory used by fts_doc_list */
ib_mutex_t mutex; /*!< mutex for fts_doc_list */
diff --git a/storage/innobase/include/row0ins.h b/storage/innobase/include/row0ins.h
index 48a3044f1d6..4038c32b9c0 100644
--- a/storage/innobase/include/row0ins.h
+++ b/storage/innobase/include/row0ins.h
@@ -97,7 +97,7 @@ row_ins_clust_index_entry_low(
bool dup_chk_only)
/*!< in: if true, just do duplicate check
and return. don't execute actual insert. */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/***************************************************************//**
Tries to insert an entry into a secondary index. If a record with exactly the
@@ -125,7 +125,7 @@ row_ins_sec_index_entry_low(
bool dup_chk_only)
/*!< in: if true, just do duplicate check
and return. don't execute actual insert. */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Sets the values of the dtuple fields in entry from the values of appropriate
columns in row.
@param[in] index index handler
@@ -178,7 +178,7 @@ row_ins_clust_index_entry(
bool dup_chk_only)
/*!< in: if true, just do duplicate check
and return. don't execute actual insert. */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/***************************************************************//**
Inserts an entry into a secondary index. Tries first optimistic,
then pessimistic descent down the tree. If the entry matches enough
@@ -194,7 +194,7 @@ row_ins_sec_index_entry(
bool dup_chk_only)
/*!< in: if true, just do duplicate check
and return. don't execute actual insert. */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/***********************************************************//**
Inserts a row to a table. This is a high-level function used in
SQL execution graphs.
diff --git a/storage/innobase/include/row0log.h b/storage/innobase/include/row0log.h
index 80571eb3b3d..c8db44f23b3 100644
--- a/storage/innobase/include/row0log.h
+++ b/storage/innobase/include/row0log.h
@@ -56,8 +56,9 @@ row_log_allocate(
const dtuple_t* add_cols,
/*!< in: default values of
added columns, or NULL */
- const ulint* col_map)/*!< in: mapping of old column
+ const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL if !table */
+ const char* path) /*!< in: where to create temporary file */
MY_ATTRIBUTE((nonnull(1), warn_unused_result));
/******************************************************//**
@@ -112,6 +113,16 @@ row_log_table_get_error(
that is being rebuilt online */
MY_ATTRIBUTE((nonnull, warn_unused_result));
+/** Check whether a virtual column is indexed in the new table being
+created during alter table
+@param[in] index cluster index
+@param[in] v_no virtual column number
+@return true if it is indexed, else false */
+bool
+row_log_col_is_indexed(
+ const dict_index_t* index,
+ ulint v_no);
+
/******************************************************//**
Logs a delete operation to a table that is being rebuilt.
This will be merged in row_log_table_apply_delete(). */
@@ -208,7 +219,7 @@ row_log_table_apply(
dict_table_t* old_table,
struct TABLE* table,
ut_stage_alter_t* stage)
-__attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/******************************************************//**
Get the latest transaction ID that has invoked row_log_online_op()
@@ -235,7 +246,7 @@ row_log_apply(
dict_index_t* index,
struct TABLE* table,
ut_stage_alter_t* stage)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifdef HAVE_PSI_STAGE_INTERFACE
/** Estimate how much work is to be done by the log apply phase
diff --git a/storage/innobase/include/row0merge.h b/storage/innobase/include/row0merge.h
index 4493df5e0bd..f3b5860910c 100644
--- a/storage/innobase/include/row0merge.h
+++ b/storage/innobase/include/row0merge.h
@@ -152,6 +152,7 @@ row_merge_dup_report(
row_merge_dup_t* dup, /*!< in/out: for reporting duplicates */
const dfield_t* entry) /*!< in: duplicate index entry */
MY_ATTRIBUTE((nonnull));
+
/*********************************************************************//**
Sets an exclusive lock on a table, for the duration of creating indexes.
@return error code or DB_SUCCESS */
@@ -161,7 +162,8 @@ row_merge_lock_table(
trx_t* trx, /*!< in/out: transaction */
dict_table_t* table, /*!< in: table to lock */
enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((nonnull(1,2), warn_unused_result));
+
/*********************************************************************//**
Drop indexes that were created before an error occurred.
The data dictionary must have been locked exclusively by the caller,
@@ -172,6 +174,7 @@ row_merge_drop_indexes_dict(
trx_t* trx, /*!< in/out: dictionary transaction */
table_id_t table_id)/*!< in: table identifier */
MY_ATTRIBUTE((nonnull));
+
/*********************************************************************//**
Drop those indexes which were created before an error occurred.
The data dictionary must have been locked exclusively by the caller,
@@ -184,6 +187,7 @@ row_merge_drop_indexes(
ibool locked) /*!< in: TRUE=table locked,
FALSE=may need to do a lazy drop */
MY_ATTRIBUTE((nonnull));
+
/*********************************************************************//**
Drop all partially created indexes during crash recovery. */
void
@@ -195,7 +199,8 @@ UNIV_PFS_IO defined, register the file descriptor with Performance Schema.
@param[in] path location for creating temporary merge files.
@return File descriptor */
int
-row_merge_file_create_low(void)
+row_merge_file_create_low(
+ const char* path)
MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Destroy a merge file. And de-register the file from Performance Schema
@@ -214,7 +219,9 @@ char*
row_make_new_pathname(
/*==================*/
dict_table_t* table, /*!< in: table to be renamed */
- const char* new_name); /*!< in: new name */
+ const char* new_name) /*!< in: new name */
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
+
/*********************************************************************//**
Rename the tables in the data dictionary. The data dictionary must
have been locked exclusively by the caller, because the transaction
@@ -242,7 +249,8 @@ row_merge_rename_index_to_add(
trx_t* trx, /*!< in/out: transaction */
table_id_t table_id, /*!< in: table identifier */
index_id_t index_id) /*!< in: index identifier */
- MY_ATTRIBUTE((nonnull));
+ MY_ATTRIBUTE((nonnull(1), warn_unused_result));
+
/*********************************************************************//**
Rename an index in the dictionary that is to be dropped. The data
dictionary must have been locked exclusively by the caller, because
@@ -254,7 +262,8 @@ row_merge_rename_index_to_drop(
trx_t* trx, /*!< in/out: transaction */
table_id_t table_id, /*!< in: table identifier */
index_id_t index_id) /*!< in: index identifier */
- MY_ATTRIBUTE((nonnull));
+ MY_ATTRIBUTE((nonnull(1), warn_unused_result));
+
/** Create the index and load in to the dictionary.
@param[in,out] trx trx (sets error_state)
@param[in,out] table the index is on this table
@@ -270,7 +279,9 @@ row_merge_create_index(
dict_table_t* table,
const index_def_t* index_def,
const dict_add_v_col_t* add_v,
- const char** col_names);
+ const char** col_names)
+ MY_ATTRIBUTE((warn_unused_result));
+
/*********************************************************************//**
Check if a transaction can use an index.
@return TRUE if index can be used by the transaction else FALSE */
@@ -278,7 +289,9 @@ ibool
row_merge_is_index_usable(
/*======================*/
const trx_t* trx, /*!< in: transaction */
- const dict_index_t* index); /*!< in: index to check */
+ const dict_index_t* index) /*!< in: index to check */
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
+
/*********************************************************************//**
Drop a table. The caller must have ensured that the background stats
thread is not processing the table. This can be done by calling
@@ -290,7 +303,7 @@ row_merge_drop_table(
/*=================*/
trx_t* trx, /*!< in: transaction */
dict_table_t* table) /*!< in: table instance to drop */
- MY_ATTRIBUTE((nonnull));
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
/** Build indexes on a table by reading a clustered index, creating a temporary
file containing index entries, merge sorting these index entries and inserting
@@ -317,6 +330,8 @@ existing order
ALTER TABLE. stage->begin_phase_read_pk() will be called at the beginning of
this function and it will be passed to other functions for further accounting.
@param[in] add_v new virtual columns added along with indexes
+@param[in] eval_table mysql table used to evaluate virtual column
+ value, see innobase_get_computed_value().
@return DB_SUCCESS or error code */
dberr_t
row_merge_build_indexes(
@@ -334,8 +349,9 @@ row_merge_build_indexes(
ib_sequence_t& sequence,
bool skip_pk_sort,
ut_stage_alter_t* stage,
- const dict_add_v_col_t* add_v)
-__attribute__((warn_unused_result));
+ const dict_add_v_col_t* add_v,
+ struct TABLE* eval_table)
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Write a buffer to a block. */
@@ -346,6 +362,7 @@ row_merge_buf_write(
const merge_file_t* of, /*!< in: output file */
row_merge_block_t* block) /*!< out: buffer for writing to file */
MY_ATTRIBUTE((nonnull));
+
/********************************************************************//**
Sort a buffer. */
void
@@ -355,6 +372,7 @@ row_merge_buf_sort(
row_merge_dup_t* dup) /*!< in/out: reporter of duplicates
(NULL if non-unique index) */
MY_ATTRIBUTE((nonnull(1)));
+
/********************************************************************//**
Write a merge block to the file system.
@return TRUE if request was successful, FALSE if fail */
@@ -367,7 +385,8 @@ row_merge_write(
const void* buf, /*!< in: data */
fil_space_crypt_t* crypt_data, /*!< in: table crypt data */
void* crypt_buf, /*!< in: crypt buf or NULL */
- ulint space); /*!< in: space id */
+ ulint space) /*!< in: space id */
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Empty a sort buffer.
@@ -384,7 +403,9 @@ row_merge_buf_empty(
@return file descriptor, or -1 on failure */
int
row_merge_file_create(
- merge_file_t* merge_file);
+ merge_file_t* merge_file,
+ const char* path)
+ MY_ATTRIBUTE((warn_unused_result, nonnull));
/** Merge disk files.
@param[in] trx transaction
@@ -392,6 +413,12 @@ row_merge_file_create(
@param[in,out] file file containing index entries
@param[in,out] block 3 buffers
@param[in,out] tmpfd temporary file handle
+@param[in] update_progress true, if we should update progress status
+@param[in] pct_progress total progress percent until now
+@param[in] pct_ocst current progress percent
+@param[in] crypt_data tale crypt data
+@param[in] crypt_block crypt buf or NULL
+@param[in] space space_id
@param[in,out] stage performance schema accounting object, used by
ALTER TABLE. If not NULL, stage->begin_phase_sort() will be called initially
and then stage->inc() will be called for each record processed.
@@ -399,21 +426,20 @@ and then stage->inc() will be called for each record processed.
dberr_t
row_merge_sort(
/*===========*/
- trx_t* trx, /*!< in: transaction */
- const row_merge_dup_t* dup, /*!< in: descriptor of
- index being created */
- merge_file_t* file, /*!< in/out: file containing
- index entries */
- row_merge_block_t* block, /*!< in/out: 3 buffers */
- int* tmpfd, /*!< in/out: temporary file handle */
- const bool update_progress, /*!< in: update progress status variable or not */
- const float pct_progress, /*!< in: total progress percent until now */
- const float pct_cost, /*!< in: current progress percent */
- fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
- row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */
- ulint space, /*!< in: space id */
+ trx_t* trx,
+ const row_merge_dup_t* dup,
+ merge_file_t* file,
+ row_merge_block_t* block,
+ int* tmpfd,
+ const bool update_progress,
+ const float pct_progress,
+ const float pct_cost,
+ fil_space_crypt_t* crypt_data,
+ row_merge_block_t* crypt_block,
+ ulint space,
ut_stage_alter_t* stage = NULL)
- __attribute__((nonnull(1,2,3,4,5)));
+ MY_ATTRIBUTE((warn_unused_result));
+
/*********************************************************************//**
Allocate a sort buffer.
@return own: sort buffer */
@@ -422,6 +448,7 @@ row_merge_buf_create(
/*=================*/
dict_index_t* index) /*!< in: secondary index */
MY_ATTRIBUTE((warn_unused_result, nonnull, malloc));
+
/*********************************************************************//**
Deallocate a sort buffer. */
void
@@ -429,6 +456,7 @@ row_merge_buf_free(
/*===============*/
row_merge_buf_t* buf) /*!< in,own: sort buffer to be freed */
MY_ATTRIBUTE((nonnull));
+
/*********************************************************************//**
Destroy a merge file. */
void
@@ -436,6 +464,7 @@ row_merge_file_destroy(
/*===================*/
merge_file_t* merge_file) /*!< in/out: merge file structure */
MY_ATTRIBUTE((nonnull));
+
/********************************************************************//**
Read a merge block from the file system.
@return TRUE if request was successful, FALSE if fail */
@@ -449,7 +478,8 @@ row_merge_read(
row_merge_block_t* buf, /*!< out: data */
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_buf, /*!< in: crypt buf or NULL */
- ulint space); /*!< in: space id */
+ ulint space) /*!< in: space id */
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Read a merge record.
@@ -470,5 +500,5 @@ row_merge_read_rec(
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */
ulint space) /*!< in: space id */
- __attribute__((nonnull(1,2,3,4,6,7,8), warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* row0merge.h */
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 5b195734be9..2d508c1a7df 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -130,7 +130,7 @@ row_mysql_read_geometry(
MySQL format */
ulint col_len) /*!< in: BLOB reference length
(not BLOB length) */
- __attribute__((nonnull(1,2), warn_unused_result));
+ MY_ATTRIBUTE((nonnull(1,2), warn_unused_result));
/**************************************************************//**
Pad a column with spaces. */
void
@@ -229,6 +229,7 @@ row_lock_table_autoinc_for_mysql(
row_prebuilt_t* prebuilt) /*!< in: prebuilt struct in the MySQL
table handle */
MY_ATTRIBUTE((nonnull, warn_unused_result));
+
/*********************************************************************//**
Sets a table lock on the table mentioned in prebuilt.
@return error code or DB_SUCCESS */
@@ -253,7 +254,7 @@ dberr_t
row_insert_for_mysql(
const byte* mysql_rec,
row_prebuilt_t* prebuilt)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Builds a dummy query graph used in selects. */
@@ -289,7 +290,7 @@ dberr_t
row_update_for_mysql(
const byte* mysql_rec,
row_prebuilt_t* prebuilt)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Delete all rows for the given table by freeing/truncating indexes.
@param[in,out] table table handler
@@ -297,7 +298,7 @@ row_update_for_mysql(
dberr_t
row_delete_all_rows(
dict_table_t* table)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** This can only be used when srv_locks_unsafe_for_binlog is TRUE or this
session is using a READ COMMITTED or READ UNCOMMITTED isolation level.
@@ -381,13 +382,14 @@ row_create_table_for_mysql(
dict_table_t* table, /*!< in, own: table definition
(will be freed, or on DB_SUCCESS
added to the data dictionary cache) */
- const char* compression,
- /*!< in: compression algorithm to use,
- can be NULL */
+ const char* compression,
+ /*!< in: compression algorithm to use,
+ can be NULL */
trx_t* trx, /*!< in/out: transaction */
bool commit, /*!< in: if true, commit the transaction */
fil_encryption_t mode, /*!< in: encryption mode */
- ulint key_id);/*!< in: encryption key_id */
+ ulint key_id) /*!< in: encryption key_id */
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Does an index creation operation for MySQL. TODO: currently failure
@@ -407,7 +409,7 @@ row_create_index_for_mysql(
then checked for not being too
large. */
dict_table_t* handler) /* ! in/out: table handler. */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Scans a table create SQL string and adds to the data dictionary
the foreign key constraints declared in the string. This function
@@ -438,7 +440,7 @@ row_table_add_foreign_constraints(
size_t sql_length,
const char* name,
ibool reject_fks)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
The master thread in srv0srv.cc calls this regularly to drop tables which
@@ -489,8 +491,8 @@ row_drop_table_for_mysql(
trx_t* trx, /*!< in: dictionary transaction handle */
bool drop_db,/*!< in: true=dropping whole database */
ibool create_failed,/*!<in: TRUE=create table failed
- because e.g. foreign key column
- type mismatch. */
+ because e.g. foreign key column
+ type mismatch. */
bool nonatomic = true,
/*!< in: whether it is permitted
to release and reacquire dict_operation_lock */
@@ -557,7 +559,7 @@ row_rename_partitions_for_mysql(
const char* old_name,
const char* new_name,
trx_t* trx)
- __attribute__((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((nonnull, warn_unused_result));
/*********************************************************************//**
Scans an index for either COOUNT(*) or CHECK TABLE.
@@ -576,7 +578,7 @@ row_scan_index_for_mysql(
false=count the rows only */
ulint* n_rows) /*!< out: number of entries
seen in the consistent read */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Initialize this module */
void
@@ -910,6 +912,14 @@ struct row_prebuilt_t {
/** Disable prefetch. */
bool m_no_prefetch;
+ /** Return materialized key for secondary index scan */
+ bool m_read_virtual_key;
+
+ /** The MySQL table object */
+ TABLE* m_mysql_table;
+
+ /** limit value to avoid fts result overflow */
+ ulonglong m_fts_limit;
};
/** Callback for row_mysql_sys_index_iterate() */
@@ -926,22 +936,42 @@ struct SysIndexCallback {
@param[in,out] row the data row
@param[in] col virtual column
@param[in] index index on the virtual column
-@param[in,out] my_rec MySQL record to store the rows
@param[in,out] local_heap heap memory for processing large data etc.
@param[in,out] heap memory heap that copies the actual index row
@param[in] ifield index field
-@param[in] in_purge whether this is called by purge
+@param[in] thd MySQL thread handle
+@param[in,out] mysql_table mysql table object
+@param[in] old_table during ALTER TABLE, this is the old table
+ or NULL.
+@param[in] parent_update update vector for the parent row
+@param[in] foreign foreign key information
@return the field filled with computed value */
dfield_t*
innobase_get_computed_value(
const dtuple_t* row,
const dict_v_col_t* col,
const dict_index_t* index,
- byte* my_rec,
mem_heap_t** local_heap,
mem_heap_t* heap,
const dict_field_t* ifield,
- bool in_purge);
+ THD* thd,
+ TABLE* mysql_table,
+ const dict_table_t* old_table,
+ upd_t* parent_update,
+ dict_foreign_t* foreign);
+
+/** Get the computed value by supplying the base column values.
+@param[in,out] table the table whose virtual column template to be built */
+void
+innobase_init_vc_templ(
+ dict_table_t* table);
+
+/** Change dbname and table name in table->vc_templ.
+@param[in,out] table the table whose virtual column template
+dbname and tbname to be renamed. */
+void
+innobase_rename_vc_templ(
+ dict_table_t* table);
#define ROW_PREBUILT_FETCH_MAGIC_N 465765687
@@ -964,4 +994,10 @@ innobase_get_computed_value(
#include "row0mysql.ic"
#endif
+#ifdef UNIV_DEBUG
+/** Wait for the background drop list to become empty. */
+void
+row_wait_for_background_drop_list_empty();
+#endif /* UNIV_DEBUG */
+
#endif /* row0mysql.h */
diff --git a/storage/innobase/include/row0purge.h b/storage/innobase/include/row0purge.h
index f640dfaf62f..32a989833bc 100644
--- a/storage/innobase/include/row0purge.h
+++ b/storage/innobase/include/row0purge.h
@@ -44,7 +44,7 @@ purge_node_t*
row_purge_node_create(
que_thr_t* parent,
mem_heap_t* heap)
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/***********************************************************//**
Determines if it is possible to remove a secondary index entry.
diff --git a/storage/innobase/include/row0row.h b/storage/innobase/include/row0row.h
index 4fd93283884..93ff90d020e 100644
--- a/storage/innobase/include/row0row.h
+++ b/storage/innobase/include/row0row.h
@@ -159,9 +159,9 @@ row_build(
row_ext_t** ext, /*!< out, own: cache of
externally stored column
prefixes, or NULL */
- mem_heap_t* heap) /*!< in: memory heap from which
+ mem_heap_t* heap); /*!< in: memory heap from which
the memory needed is allocated */
- MY_ATTRIBUTE((nonnull(2,3,9)));
+
/** An inverse function to row_build_index_entry. Builds a row from a
record in a clustered index, with possible indexing on ongoing
addition of new virtual columns.
@@ -212,7 +212,7 @@ row_rec_to_index_entry_low(
stored columns */
mem_heap_t* heap) /*!< in: memory heap from which
the memory needed is allocated */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Converts an index record to a typed data tuple. NOTE that externally
stored (often big) fields are NOT copied to heap.
@@ -227,7 +227,7 @@ row_rec_to_index_entry(
stored columns */
mem_heap_t* heap) /*!< in: memory heap from which
the memory needed is allocated */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Builds from a secondary index record a row reference with which we can
search the clustered index record.
@@ -249,7 +249,7 @@ row_build_row_ref(
as long as the row reference is used! */
mem_heap_t* heap) /*!< in: memory heap from which the memory
needed is allocated */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*******************************************************************//**
Builds from a secondary index record a row reference with which we can
search the clustered index record. */
diff --git a/storage/innobase/include/row0sel.h b/storage/innobase/include/row0sel.h
index 1d308320b6f..3e6863208af 100644
--- a/storage/innobase/include/row0sel.h
+++ b/storage/innobase/include/row0sel.h
@@ -174,7 +174,7 @@ row_search_for_mysql(
row_prebuilt_t* prebuilt,
ulint match_mode,
ulint direction)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Searches for rows in the database using cursor.
function is meant for temporary table that are not shared accross connection
@@ -201,7 +201,7 @@ row_search_no_mvcc(
row_prebuilt_t* prebuilt,
ulint match_mode,
ulint direction)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Searches for rows in the database using cursor.
Function is mainly used for tables that are shared accorss connection and
@@ -238,7 +238,7 @@ row_search_mvcc(
row_prebuilt_t* prebuilt,
ulint match_mode,
ulint direction)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/********************************************************************//**
Count rows in a R-Tree leaf level.
@@ -253,10 +253,9 @@ row_count_rtree_recs(
position the cursor at the start or
the end of the index, depending on
'mode' */
- ulint* n_rows) /*!< out: number of entries
+ ulint* n_rows); /*!< out: number of entries
seen in the consistent read */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
/*******************************************************************//**
Checks if MySQL at the moment is allowed for this table to retrieve a
consistent read result, or store it to the query cache.
diff --git a/storage/innobase/include/row0umod.h b/storage/innobase/include/row0umod.h
index 11430952036..a1bb42035a9 100644
--- a/storage/innobase/include/row0umod.h
+++ b/storage/innobase/include/row0umod.h
@@ -42,7 +42,7 @@ row_undo_mod(
/*=========*/
undo_node_t* node, /*!< in: row undo node */
que_thr_t* thr) /*!< in: query thread */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#ifndef UNIV_NONINL
#include "row0umod.ic"
diff --git a/storage/innobase/include/row0undo.h b/storage/innobase/include/row0undo.h
index 1f700e441c7..3d5b3574afa 100644
--- a/storage/innobase/include/row0undo.h
+++ b/storage/innobase/include/row0undo.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -56,7 +56,7 @@ bool
row_undo_search_clust_to_pcur(
/*==========================*/
undo_node_t* node) /*!< in/out: row undo node */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/***********************************************************//**
Undoes a row operation in a table. This is a high-level function used
in SQL execution graphs.
diff --git a/storage/innobase/include/row0upd.h b/storage/innobase/include/row0upd.h
index 84a10c0f4c9..3c1033fe419 100644
--- a/storage/innobase/include/row0upd.h
+++ b/storage/innobase/include/row0upd.h
@@ -112,8 +112,8 @@ upd_get_field_by_field_no(
/*======================*/
const upd_t* update, /*!< in: update vector */
ulint no, /*!< in: field_no */
- bool is_virtual) /*!< in: if it is a virtual column */
- MY_ATTRIBUTE((warn_unused_result, nonnull, pure));
+ bool is_virtual) /*!< in: if it is a virtual column */
+ MY_ATTRIBUTE((warn_unused_result));
/*********************************************************************//**
Writes into the redo log the values of trx id and roll ptr and enough info
to determine their positions within a clustered index record.
@@ -222,24 +222,32 @@ row_upd_build_sec_rec_difference_binary(
const dtuple_t* entry, /*!< in: entry to insert */
mem_heap_t* heap) /*!< in: memory heap from which allocated */
MY_ATTRIBUTE((warn_unused_result, nonnull));
-/***************************************************************//**
-Builds an update vector from those fields, excluding the roll ptr and
+/** Builds an update vector from those fields, excluding the roll ptr and
trx id fields, which in an index entry differ from a record that has
the equal ordering fields. NOTE: we compare the fields as binary strings!
+@param[in] index clustered index
+@param[in] entry clustered index entry to insert
+@param[in] rec clustered index record
+@param[in] offsets rec_get_offsets(rec,index), or NULL
+@param[in] no_sys skip the system columns
+ DB_TRX_ID and DB_ROLL_PTR
+@param[in] trx transaction (for diagnostics),
+ or NULL
+@param[in] heap memory heap from which allocated
+@param[in,out] mysql_table NULL, or mysql table object when
+ user thread invokes dml
@return own: update vector of differing fields, excluding roll ptr and
trx id */
upd_t*
row_upd_build_difference_binary(
-/*============================*/
- dict_index_t* index, /*!< in: clustered index */
- const dtuple_t* entry, /*!< in: entry to insert */
- const rec_t* rec, /*!< in: clustered index record */
- const ulint* offsets,/*!< in: rec_get_offsets(rec,index), or NULL */
- bool no_sys, /*!< in: skip the system columns
- DB_TRX_ID and DB_ROLL_PTR */
- trx_t* trx, /*!< in: transaction (for diagnostics),
- or NULL */
- mem_heap_t* heap) /*!< in: memory heap from which allocated */
+ dict_index_t* index,
+ const dtuple_t* entry,
+ const rec_t* rec,
+ const ulint* offsets,
+ bool no_sys,
+ trx_t* trx,
+ mem_heap_t* heap,
+ TABLE* mysql_table)
MY_ATTRIBUTE((nonnull(1,2,3,7), warn_unused_result));
/***********************************************************//**
Replaces the new column values stored in the update vector to the index entry
@@ -377,12 +385,16 @@ row_upd_changes_some_index_ord_field_binary(
/*========================================*/
const dict_table_t* table, /*!< in: table */
const upd_t* update);/*!< in: update vector for the row */
-/***********************************************************//**
-Stores to the heap the row on which the node->pcur is positioned. */
+/** Stores to the heap the row on which the node->pcur is positioned.
+@param[in] node row update node
+@param[in] thd mysql thread handle
+@param[in,out] mysql_table NULL, or mysql table object when
+ user thread invokes dml */
void
row_upd_store_row(
-/*==============*/
- upd_node_t* node); /*!< in: row update node */
+ upd_node_t* node,
+ THD* thd,
+ TABLE* mysql_table);
/***********************************************************//**
Updates a row in a table. This is a high-level function used
in SQL execution graphs.
@@ -434,7 +446,9 @@ struct upd_field_t{
the clustered index, but in updating
a secondary index record in btr0cur.cc
this is the position in the secondary
- index */
+ index. If this field is a virtual
+ column, then field_no represents
+ the nth virtual column in the table */
#ifndef UNIV_HOTBACKUP
unsigned orig_len:16; /*!< original length of the locally
stored part of an externally stored
@@ -515,11 +529,6 @@ struct upd_node_t{
ibool in_mysql_interface;
/* TRUE if the update node was created
for the MySQL interface */
- upd_node_t* cascade_node;/* NULL or an update node template which
- is used to implement ON DELETE/UPDATE CASCADE
- or ... SET NULL for foreign keys */
- mem_heap_t* cascade_heap;/* NULL or a mem heap where the cascade
- node is created */
dict_foreign_t* foreign;/* NULL or pointer to a foreign key
constraint if this update node is used in
doing an ON DELETE or ON UPDATE operation */
@@ -550,6 +559,11 @@ struct upd_node_t{
cascade nodes are stored here, so that memory
can be freed. */
+ mem_heap_t* cascade_heap;
+ /*!< NULL or a mem heap where cascade_upd_nodes
+ are created. This heap is owned by the node
+ that has cascade_top=true. */
+
sel_node_t* select; /*!< query graph subtree implementing a base
table cursor: the rows returned will be
updated */
diff --git a/storage/innobase/include/row0vers.h b/storage/innobase/include/row0vers.h
index cd476acb6a1..489db305fac 100644
--- a/storage/innobase/include/row0vers.h
+++ b/storage/innobase/include/row0vers.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -118,8 +118,7 @@ row_vers_build_for_consistent_read(
if the history is missing or the record
does not exist in the view, that is,
it was freshly inserted afterwards */
- const dtuple_t**vrow) /*!< out: reports virtual column info if any */
- MY_ATTRIBUTE((nonnull(1,2,3,4,5,6,7)));
+ const dtuple_t**vrow); /*!< out: reports virtual column info if any */
/*****************************************************************//**
Constructs the last committed version of a clustered index record,
@@ -144,9 +143,9 @@ row_vers_build_for_semi_consistent_read(
const rec_t** old_vers,/*!< out: rec, old version, or NULL if the
record does not exist in the view, that is,
it was freshly inserted afterwards */
- const dtuple_t**vrow) /*!< out: holds virtual column info if any
+ const dtuple_t**vrow); /*!< out: holds virtual column info if any
is updated in the view */
- MY_ATTRIBUTE((nonnull(1,2,3,4,5)));
+
#ifndef UNIV_NONINL
#include "row0vers.ic"
diff --git a/storage/innobase/include/srv0mon.h b/storage/innobase/include/srv0mon.h
index 2dee270df4c..14c1d62c127 100644
--- a/storage/innobase/include/srv0mon.h
+++ b/storage/innobase/include/srv0mon.h
@@ -107,8 +107,14 @@ enum monitor_type_t {
/** Counter minimum value is initialized to be max value of
mon_type_t (int64_t) */
-#define MIN_RESERVED INT_MAX64
-#define MAX_RESERVED (~MIN_RESERVED)
+#ifndef INT64_MAX
+#define INT64_MAX (9223372036854775807LL)
+#endif
+#ifndef INT64_MIN
+#define INT64_MIN (-9223372036854775807LL-1)
+#endif
+#define MIN_RESERVED INT64_MAX
+#define MAX_RESERVED INT64_MIN
/** This enumeration defines internal monitor identifier used internally
to identify each particular counter. Its value indexes into two arrays,
diff --git a/storage/innobase/include/srv0srv.h b/storage/innobase/include/srv0srv.h
index 2c46f7ce3ae..be6461edec1 100644
--- a/storage/innobase/include/srv0srv.h
+++ b/storage/innobase/include/srv0srv.h
@@ -58,6 +58,8 @@ Created 10/10/1995 Heikki Tuuri
#include "ut0counter.h"
#include "fil0fil.h"
+struct fil_space_t;
+
/* Global counters used inside InnoDB. */
struct srv_stats_t {
typedef ib_counter_t<ulint, 64> ulint_ctr_64_t;
@@ -297,8 +299,8 @@ extern my_bool srv_use_atomic_writes;
extern ulong innodb_compression_algorithm;
/* Number of flush threads */
-#define MTFLUSH_MAX_WORKER 64
-#define MTFLUSH_DEFAULT_WORKER 8
+#define MTFLUSH_MAX_WORKER 64
+#define MTFLUSH_DEFAULT_WORKER 8
/* Number of threads used for multi-threaded flush */
extern long srv_mtflush_threads;
@@ -372,6 +374,7 @@ extern my_bool srv_flush_sync;
/* When this event is reset we do not allow any file writes to take place. */
extern os_event_t srv_allow_writes_event;
#endif /* WITH_INNODB_DISALLOW_WRITES */
+
/* If this flag is TRUE, then we will load the indexes' (and tables') metadata
even if they are marked as "corrupted". Mostly it is for DBA to process
corrupted index and table */
@@ -414,6 +417,7 @@ extern my_bool srv_random_read_ahead;
extern ulong srv_read_ahead_threshold;
extern ulint srv_n_read_io_threads;
extern ulint srv_n_write_io_threads;
+
/* Defragmentation, Origianlly facebook default value is 100, but it's too high */
#define SRV_DEFRAGMENT_FREQUENCY_DEFAULT 40
extern my_bool srv_defragment;
@@ -481,6 +485,7 @@ extern my_bool srv_stats_sample_traditional;
extern ibool srv_use_doublewrite_buf;
extern ulong srv_doublewrite_batch_size;
+extern ulong srv_checksum_algorithm;
extern double srv_max_buf_pool_modified_pct;
extern my_bool srv_force_primary_key;
@@ -529,6 +534,9 @@ extern my_bool srv_ibuf_disable_background_merge;
#ifdef UNIV_DEBUG
extern my_bool srv_sync_debug;
extern my_bool srv_purge_view_update_only_debug;
+
+/** Value of MySQL global used to disable master thread. */
+extern my_bool srv_master_thread_disabled_debug;
#endif /* UNIV_DEBUG */
#define SRV_SEMAPHORE_WAIT_EXTENSION 7200
@@ -594,6 +602,7 @@ extern mysql_pfs_key_t srv_lock_timeout_thread_key;
extern mysql_pfs_key_t srv_master_thread_key;
extern mysql_pfs_key_t srv_monitor_thread_key;
extern mysql_pfs_key_t srv_purge_thread_key;
+extern mysql_pfs_key_t srv_worker_thread_key;
extern mysql_pfs_key_t trx_rollback_clean_thread_key;
/* This macro register the current thread and its key with performance
@@ -951,11 +960,26 @@ bool
srv_is_tablespace_truncated(ulint space_id);
/** Check if tablespace was truncated.
-@param space_id space_id to check for truncate action
+@param[in] space space object to check for truncate action
@return true if tablespace was truncated and we still have an active
MLOG_TRUNCATE REDO log record. */
bool
-srv_was_tablespace_truncated(ulint space_id);
+srv_was_tablespace_truncated(const fil_space_t* space);
+
+#ifdef UNIV_DEBUG
+/** Disables master thread. It's used by:
+ SET GLOBAL innodb_master_thread_disabled_debug = 1 (0).
+@param[in] thd thread handle
+@param[in] var pointer to system variable
+@param[out] var_ptr where the formal string goes
+@param[in] save immediate result from check function */
+void
+srv_master_thread_disabled_debug_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save);
+#endif /* UNIV_DEBUG */
/** Status variables to be passed to MySQL */
struct export_var_t{
@@ -990,6 +1014,7 @@ struct export_var_t{
ulint innodb_buffer_pool_read_ahead_evicted;/*!< srv_read_ahead evicted*/
ulint innodb_dblwr_pages_written; /*!< srv_dblwr_pages_written */
ulint innodb_dblwr_writes; /*!< srv_dblwr_writes */
+ ibool innodb_have_atomic_builtins; /*!< HAVE_ATOMIC_BUILTINS */
ulint innodb_log_waits; /*!< srv_log_waits */
ulint innodb_log_write_requests; /*!< srv_log_write_requests */
ulint innodb_log_writes; /*!< srv_log_writes */
@@ -1136,6 +1161,7 @@ struct srv_slot_t{
# define srv_start_raw_disk_in_use 0
# define srv_file_per_table 1
#endif /* !UNIV_HOTBACKUP */
+
#ifdef WITH_WSREP
UNIV_INTERN
void
diff --git a/storage/innobase/include/srv0start.h b/storage/innobase/include/srv0start.h
index 9db27ef2965..0dd98e5b19b 100644
--- a/storage/innobase/include/srv0start.h
+++ b/storage/innobase/include/srv0start.h
@@ -125,6 +125,17 @@ srv_get_meta_data_filename(
char* filename,
ulint max_len);
+/** Get the encryption-data filename from the table name for a
+single-table tablespace.
+@param[in] table table object
+@param[out] filename filename
+@param[in] max_len filename max length */
+void
+srv_get_encryption_data_filename(
+ dict_table_t* table,
+ char* filename,
+ ulint max_len);
+
/** Log sequence number at shutdown */
extern lsn_t srv_shutdown_lsn;
/** Log sequence number immediately after startup */
diff --git a/storage/innobase/include/sync0arr.h b/storage/innobase/include/sync0arr.h
index db04e0e7b22..1a3cc93f0e9 100644
--- a/storage/innobase/include/sync0arr.h
+++ b/storage/innobase/include/sync0arr.h
@@ -1,6 +1,7 @@
/*****************************************************************************
-Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2015, 2016, MariaDB Corporation.
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
@@ -29,7 +30,7 @@ Created 9/5/1995 Heikki Tuuri
#include "univ.i"
#include "os0thread.h"
-/** Synchonization cell */
+/** Synchronization wait array cell */
struct sync_cell_t;
/** Synchronization wait array */
@@ -128,7 +129,6 @@ Get an instance of the sync wait array. */
UNIV_INLINE
sync_array_t*
sync_array_get();
-
/**********************************************************************//**
Prints info of the wait array without using any mutexes/semaphores. */
UNIV_INTERN
diff --git a/storage/innobase/include/sync0rw.h b/storage/innobase/include/sync0rw.h
index 8e76af327a4..64bbf4c4aac 100644
--- a/storage/innobase/include/sync0rw.h
+++ b/storage/innobase/include/sync0rw.h
@@ -171,6 +171,18 @@ unlocking, not the corresponding function. */
#define rw_lock_sx_lock_nowait(M, P) \
rw_lock_sx_lock_low((M), (P), __FILE__, __LINE__)
+#define rw_lock_sx_lock(L) \
+ rw_lock_sx_lock_func((L), 0, __FILE__, __LINE__)
+
+#define rw_lock_sx_lock_inline(M, P, F, L) \
+ rw_lock_sx_lock_func((M), (P), (F), (L))
+
+#define rw_lock_sx_lock_gen(M, P) \
+ rw_lock_sx_lock_func((M), (P), __FILE__, __LINE__)
+
+#define rw_lock_sx_lock_nowait(M, P) \
+ rw_lock_sx_lock_low((M), (P), __FILE__, __LINE__)
+
# ifdef UNIV_DEBUG
# define rw_lock_sx_unlock(L) rw_lock_sx_unlock_func(0, L)
# define rw_lock_sx_unlock_gen(L, P) rw_lock_sx_unlock_func(P, L)
@@ -552,7 +564,7 @@ rw_lock_own_flagged(
const rw_lock_t* lock, /*!< in: rw-lock */
rw_lock_flags_t flags) /*!< in: specify lock types with
OR of the rw_lock_flag_t values */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */
/******************************************************************//**
Checks if somebody has locked the rw-lock in the specified mode.
diff --git a/storage/innobase/include/sync0sync.h b/storage/innobase/include/sync0sync.h
index b6a80e8a93c..7fddada10f8 100644
--- a/storage/innobase/include/sync0sync.h
+++ b/storage/innobase/include/sync0sync.h
@@ -70,6 +70,7 @@ extern mysql_pfs_key_t ibuf_bitmap_mutex_key;
extern mysql_pfs_key_t ibuf_mutex_key;
extern mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key;
extern mysql_pfs_key_t log_sys_mutex_key;
+extern mysql_pfs_key_t log_sys_write_mutex_key;
extern mysql_pfs_key_t log_cmdq_mutex_key;
extern mysql_pfs_key_t log_flush_order_mutex_key;
extern mysql_pfs_key_t mutex_list_mutex_key;
@@ -135,9 +136,7 @@ extern mysql_pfs_key_t index_online_log_key;
extern mysql_pfs_key_t dict_table_stats_key;
extern mysql_pfs_key_t trx_sys_rw_lock_key;
extern mysql_pfs_key_t hash_table_locks_key;
-# ifdef UNIV_DEBUG
-extern mysql_pfs_key_t buf_chunk_map_latch_key;
-# endif /* UNIV_DEBUG */
+extern mysql_pfs_key_t master_key_id_mutex_key;
#endif /* UNIV_PFS_RWLOCK */
/** Prints info of the sync system.
diff --git a/storage/innobase/include/sync0types.h b/storage/innobase/include/sync0types.h
index 10f1a6e9d6f..0036135c1f0 100644
--- a/storage/innobase/include/sync0types.h
+++ b/storage/innobase/include/sync0types.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -223,6 +223,7 @@ enum latch_level_t {
SYNC_POOL,
SYNC_POOL_MANAGER,
+
SYNC_SEARCH_SYS,
SYNC_WORK_QUEUE,
@@ -234,6 +235,7 @@ enum latch_level_t {
SYNC_RECV,
SYNC_LOG_FLUSH_ORDER,
SYNC_LOG,
+ SYNC_LOG_WRITE,
SYNC_PAGE_CLEANER,
SYNC_PURGE_QUEUE,
SYNC_TRX_SYS_HEADER,
@@ -324,6 +326,7 @@ enum latch_id_t {
LATCH_ID_IBUF,
LATCH_ID_IBUF_PESSIMISTIC_INSERT,
LATCH_ID_LOG_SYS,
+ LATCH_ID_LOG_WRITE,
LATCH_ID_LOG_FLUSH_ORDER,
LATCH_ID_LIST,
LATCH_ID_MUTEX_LIST,
@@ -386,8 +389,10 @@ enum latch_id_t {
LATCH_ID_HASH_TABLE_RW_LOCK,
LATCH_ID_BUF_CHUNK_MAP_LATCH,
LATCH_ID_SYNC_DEBUG_MUTEX,
+ LATCH_ID_MASTER_KEY_ID_MUTEX,
LATCH_ID_SCRUB_STAT_MUTEX,
LATCH_ID_DEFRAGMENT_MUTEX,
+ LATCH_ID_BTR_DEFRAGMENT_MUTEX,
LATCH_ID_MTFLUSH_THREAD_MUTEX,
LATCH_ID_MTFLUSH_MUTEX,
LATCH_ID_FIL_CRYPT_MUTEX,
diff --git a/storage/innobase/include/trx0rec.h b/storage/innobase/include/trx0rec.h
index 24c36825dd7..b7a2deac63e 100644
--- a/storage/innobase/include/trx0rec.h
+++ b/storage/innobase/include/trx0rec.h
@@ -331,6 +331,9 @@ info, and verify the column is still indexed, and output its position
@param[in] ptr undo log pointer
@param[in] first_v_col if this is the first virtual column, which
has the version marker
+@param[in,out] is_undo_log his function is used to parse both undo log,
+ and online log for virtual columns. So
+ check to see if this is undo log
@param[out] field_no the column number
@return remaining part of undo log record after reading these values */
const byte*
@@ -338,6 +341,7 @@ trx_undo_read_v_idx(
const dict_table_t* table,
const byte* ptr,
bool first_v_col,
+ bool* is_undo_log,
ulint* field_no);
#ifndef UNIV_HOTBACKUP
diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h
index e0d6c4f1da6..b9cbd387a62 100644
--- a/storage/innobase/include/trx0rseg.h
+++ b/storage/innobase/include/trx0rseg.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -122,9 +122,8 @@ rseg array in trx_sys at a database startup. */
void
trx_rseg_array_init(
/*================*/
- trx_sysf_t* sys_header, /*!< in/out: trx system header */
- purge_pq_t* purge_queue, /*!< in: rseg queue */
- mtr_t* mtr); /*!< in/out: mtr */
+ purge_pq_t* purge_queue); /*!< in: rseg queue */
+
/***************************************************************************
Free's an instance of the rollback segment in memory. */
void
diff --git a/storage/innobase/include/trx0sys.h b/storage/innobase/include/trx0sys.h
index 7d26bf5b23e..ddf535158b6 100644
--- a/storage/innobase/include/trx0sys.h
+++ b/storage/innobase/include/trx0sys.h
@@ -252,7 +252,7 @@ bool
trx_in_rw_trx_list(
/*============*/
const trx_t* in_trx) /*!< in: transaction */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */
#if defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
/***********************************************************//**
@@ -277,9 +277,7 @@ trx_sys_update_mysql_binlog_offset(
int64_t offset, /*!< in: position in that log file */
ulint field, /*!< in: offset of the MySQL log info field in
the trx sys header */
-#ifdef WITH_WSREP
trx_sysf_t* sys_header, /*!< in: trx sys header */
-#endif /* WITH_WSREP */
mtr_t* mtr); /*!< in: mtr */
/*****************************************************************//**
Prints to stderr the MySQL binlog offset info in the trx system header if
@@ -291,25 +289,29 @@ trx_sys_print_mysql_binlog_offset(void);
/** Update WSREP checkpoint XID in sys header. */
void
trx_sys_update_wsrep_checkpoint(
- const XID* xid, /*!< in: WSREP XID */
- trx_sysf_t* sys_header, /*!< in: sys_header */
- mtr_t* mtr); /*!< in: mtr */
+/*============================*/
+ const XID* xid, /*!< in: WSREP XID */
+ trx_sysf_t* sys_header, /*!< in: sys_header */
+ mtr_t* mtr); /*!< in: mtr */
void
/** Read WSREP checkpoint XID from sys header. */
trx_sys_read_wsrep_checkpoint(
- XID* xid); /*!< out: WSREP XID */
+/*==========================*/
+ XID* xid); /*!< out: WSREP XID */
#endif /* WITH_WSREP */
-/*****************************************************************//**
-Initializes the tablespace tag system. */
+
+/** Initializes the tablespace tag system. */
void
trx_sys_file_format_init(void);
/*==========================*/
+
/*****************************************************************//**
Closes the tablespace tag system. */
void
trx_sys_file_format_close(void);
/*===========================*/
+
/********************************************************************//**
Tags the system table space with minimum format id if it has not been
tagged yet.
@@ -318,6 +320,7 @@ redo log application during recovery has finished. */
void
trx_sys_file_format_tag_init(void);
/*==============================*/
+
/*****************************************************************//**
Shutdown/Close the transaction system. */
void
diff --git a/storage/innobase/include/trx0sys.ic b/storage/innobase/include/trx0sys.ic
index 2b1ff55c228..6158aea0c48 100644
--- a/storage/innobase/include/trx0sys.ic
+++ b/storage/innobase/include/trx0sys.ic
@@ -105,9 +105,11 @@ trx_sysf_get(
block = buf_page_get(page_id_t(TRX_SYS_SPACE, TRX_SYS_PAGE_NO),
univ_page_size, RW_X_LATCH, mtr);
- buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
+ if (block) {
+ buf_block_dbg_add_level(block, SYNC_TRX_SYS_HEADER);
- header = TRX_SYS + buf_block_get_frame(block);
+ header = TRX_SYS + buf_block_get_frame(block);
+ }
return(header);
}
@@ -423,7 +425,7 @@ trx_sys_get_new_trx_id()
{
#ifndef WITH_WSREP
/* wsrep_fake_trx_id violates this assert */
- ut_ad(mutex_own(&trx_sys->mutex));
+ ut_ad(trx_sys_mutex_own());
#endif /* WITH_WSREP */
/* VERY important: after the database is started, max_trx_id value is
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 3c53c45a720..839c3d057e7 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -247,17 +247,16 @@ Commits a transaction. */
void
trx_commit(
/*=======*/
- trx_t* trx) /*!< in/out: transaction */
- MY_ATTRIBUTE((nonnull));
+ trx_t* trx); /*!< in/out: transaction */
+
/****************************************************************//**
Commits a transaction and a mini-transaction. */
void
trx_commit_low(
/*===========*/
trx_t* trx, /*!< in/out: transaction */
- mtr_t* mtr) /*!< in/out: mini-transaction (will be committed),
+ mtr_t* mtr); /*!< in/out: mini-transaction (will be committed),
or NULL if trx made no modifications */
- MY_ATTRIBUTE((nonnull(1)));
/****************************************************************//**
Cleans up a transaction at database startup. The cleanup is needed if
the transaction already got to the middle of a commit when the database
@@ -299,15 +298,14 @@ holding lock_sys->mutex */
trx_t *
trx_get_trx_by_xid(
/*===============*/
- const XID* xid); /*!< in: X/Open XA transaction identifier */
+ XID* xid); /*!< in: X/Open XA transaction identifier */
/**********************************************************************//**
If required, flushes the log to disk if we called trx_commit_for_mysql()
with trx->flush_log_later == TRUE. */
void
trx_commit_complete_for_mysql(
/*==========================*/
- trx_t* trx) /*!< in/out: transaction */
- MY_ATTRIBUTE((nonnull));
+ trx_t* trx); /*!< in/out: transaction */
/**********************************************************************//**
Marks the latest SQL statement ended. */
void
@@ -377,9 +375,8 @@ trx_print_low(
/*!< in: lock_number_of_rows_locked(&trx->lock) */
ulint n_trx_locks,
/*!< in: length of trx->lock.trx_locks */
- ulint heap_size)
+ ulint heap_size);
/*!< in: mem_heap_get_size(trx->lock.lock_heap) */
- MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Prints info about a transaction.
@@ -390,9 +387,8 @@ trx_print_latched(
/*==============*/
FILE* f, /*!< in: output stream */
const trx_t* trx, /*!< in: transaction */
- ulint max_query_len) /*!< in: max query length to print,
+ ulint max_query_len); /*!< in: max query length to print,
or 0 to use the default max length */
- MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Prints info about a transaction.
@@ -402,9 +398,8 @@ trx_print(
/*======*/
FILE* f, /*!< in: output stream */
const trx_t* trx, /*!< in: transaction */
- ulint max_query_len) /*!< in: max query length to print,
+ ulint max_query_len); /*!< in: max query length to print,
or 0 to use the default max length */
- MY_ATTRIBUTE((nonnull));
/**********************************************************************//**
Determine if a transaction is a dictionary operation.
@@ -414,7 +409,7 @@ enum trx_dict_op_t
trx_get_dict_operation(
/*===================*/
const trx_t* trx) /*!< in: transaction */
- MY_ATTRIBUTE((warn_unused_result, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/**********************************************************************//**
Flag a transaction a dictionary operation. */
UNIV_INLINE
@@ -438,7 +433,7 @@ trx_state_eq(
/*=========*/
const trx_t* trx, /*!< in: transaction */
trx_state_t state) /*!< in: state */
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
# ifdef UNIV_DEBUG
/**********************************************************************//**
Asserts that a transaction has been started.
@@ -448,7 +443,7 @@ ibool
trx_assert_started(
/*===============*/
const trx_t* trx) /*!< in: transaction */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
# endif /* UNIV_DEBUG */
/**********************************************************************//**
@@ -1055,10 +1050,7 @@ struct trx_t {
the coordinator using the XA API, and
is set to false after commit or
rollback. */
- unsigned active_commit_ordered:1;/* 1 if owns prepare mutex, if
- this is set to 1 then registered should
- also be set to 1. This is used in the
- XA code */
+ unsigned active_commit_ordered:1;/* 1 if owns prepare mutex */
/*------------------------------*/
bool check_unique_secondary;
/*!< normally TRUE, but if the user
@@ -1067,11 +1059,7 @@ struct trx_t {
for secondary indexes when we decide
if we can use the insert buffer for
them, we set this FALSE */
- bool support_xa; /*!< normally we do the XA two-phase
- commit steps, but by setting this to
- FALSE, one can save CPU time and about
- 150 bytes in the undo log size as then
- we skip XA steps */
+ bool support_xa; /*!< normally we do the XA two-phase */
bool flush_log_later;/* In 2PC, we hold the
prepare_commit mutex across
both phases. In that case, we
@@ -1570,18 +1558,30 @@ private:
{
ut_ad(trx_mutex_own(trx));
- while (is_forced_rollback(trx)) {
-
- if (!is_started(trx)) {
+ ulint loop_count = 0;
+ /* start with optimistic sleep time - 20 micro seconds. */
+ ulint sleep_time = 20;
- return;
- }
+ while (is_forced_rollback(trx)) {
/* Wait for the async rollback to complete */
trx_mutex_exit(trx);
- os_thread_sleep(20);
+ loop_count++;
+ /* If the wait is long, don't hog the cpu. */
+ if (loop_count < 100) {
+ /* 20 microseconds */
+ sleep_time = 20;
+ } else if (loop_count < 1000) {
+ /* 1 millisecond */
+ sleep_time = 1000;
+ } else {
+ /* 100 milliseconds */
+ sleep_time = 100000;
+ }
+
+ os_thread_sleep(sleep_time);
trx_mutex_enter(trx);
}
diff --git a/storage/innobase/include/trx0types.h b/storage/innobase/include/trx0types.h
index e9de23862af..37a53f900eb 100644
--- a/storage/innobase/include/trx0types.h
+++ b/storage/innobase/include/trx0types.h
@@ -37,7 +37,7 @@ Created 3/26/1996 Heikki Tuuri
//#include <unordered_set>
/** printf(3) format used for printing DB_TRX_ID and other system fields */
-#define TRX_ID_FMT UINT32PF
+#define TRX_ID_FMT IB_ID_FMT
/** maximum length that a formatted trx_t::id could take, not including
the terminating NUL character. */
diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h
index e1024271606..60fbb9d2304 100644
--- a/storage/innobase/include/trx0undo.h
+++ b/storage/innobase/include/trx0undo.h
@@ -1,7 +1,6 @@
/*****************************************************************************
Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
-Copyright (c) 2013, 2016, MariaDB Corporation
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -28,7 +27,6 @@ Created 3/26/1996 Heikki Tuuri
#define trx0undo_h
#ifndef UNIV_INNOCHECKSUM
-
#include "univ.i"
#include "trx0types.h"
#include "mtr0mtr.h"
@@ -76,7 +74,7 @@ bool
trx_undo_trx_id_is_insert(
/*======================*/
const byte* trx_id) /*!< in: DB_TRX_ID, followed by DB_ROLL_PTR */
- MY_ATTRIBUTE((nonnull, pure, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* !UNIV_HOTBACKUP */
/*****************************************************************//**
Writes a roll ptr to an index page. In case that the size changes in
@@ -249,13 +247,16 @@ trx_undo_free_last_page_func(
Truncates an undo log from the end. This function is used during a rollback
to free space from an undo log. */
void
-trx_undo_truncate_end(
+trx_undo_truncate_end_func(
/*=======================*/
trx_t* trx, /*!< in: transaction whose undo log it is */
trx_undo_t* undo, /*!< in/out: undo log */
undo_no_t limit) /*!< in: all undo records with undo number
>= this value should be truncated */
- MY_ATTRIBUTE((nonnull));
+ MY_ATTRIBUTE((nonnull(1,2)));
+
+#define trx_undo_truncate_end(trx, undo, limit) \
+ trx_undo_truncate_end_func(trx, undo, limit)
/** Truncate the head of an undo log.
NOTE that only whole pages are freed; the header page is not
diff --git a/storage/innobase/include/univ.i b/storage/innobase/include/univ.i
index 0d3a3a0dfcc..6907bfec583 100644
--- a/storage/innobase/include/univ.i
+++ b/storage/innobase/include/univ.i
@@ -2,7 +2,7 @@
Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
-Copyright (c) 2013, 2015, MariaDB Corporation.
+Copyright (c) 2013, 2016, MariaDB Corporation.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -45,7 +45,7 @@ Created 1/20/1994 Heikki Tuuri
#define INNODB_VERSION_MAJOR 5
#define INNODB_VERSION_MINOR 7
-#define INNODB_VERSION_BUGFIX 9
+#define INNODB_VERSION_BUGFIX 14
/* The following is the InnoDB version as shown in
SELECT plugin_version FROM information_schema.plugins;
@@ -199,7 +199,7 @@ command. */
#define UNIV_ENABLE_UNIT_TEST_ROW_RAW_FORMAT_INT
*/
-#if defined(HAVE_valgrind)&& defined(HAVE_VALGRIND_MEMCHECK_H)
+#if defined HAVE_VALGRIND
# define UNIV_DEBUG_VALGRIND
#endif /* HAVE_VALGRIND */
#if 0
@@ -259,13 +259,20 @@ and the insert buffer must be empty when the database is started */
that are only referenced from within InnoDB, not from MySQL. We disable the
GCC visibility directive on all Sun operating systems because there is no
easy way to get it to work. See http://bugs.mysql.com/bug.php?id=52263. */
-#define MY_ATTRIBUTE __attribute__
#if defined(__GNUC__) && (__GNUC__ >= 4) && !defined(sun) || defined(__INTEL_COMPILER)
-# define UNIV_INTERN MY_ATTRIBUTE((visibility ("hidden")))
+# define UNIV_INTERN __attribute__((visibility ("hidden")))
#else
# define UNIV_INTERN
#endif
+#ifndef MY_ATTRIBUTE
+#if defined(__GNUC__)
+# define MY_ATTRIBUTE(A) __attribute__(A)
+#else
+# define MY_ATTRIBUTE(A)
+#endif
+#endif
+
#if defined(COMPILER_HINTS) \
&& defined __GNUC__ \
&& (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3)
@@ -482,30 +489,27 @@ macro ULINTPF. */
#ifdef _WIN32
/* Use the integer types and formatting strings defined in Visual Studio. */
-# define UINT32PF "%lu"
+# define UINT32PF "%u"
# define UINT64PF "%llu"
# define UINT64PFx "%016llx"
+# define UINT64scan "llu"
typedef unsigned __int64 ib_uint64_t;
typedef unsigned __int32 ib_uint32_t;
#else
-// JAN: TODO: Use formating strings defined in the C99 standard
-/* Use the integer types and formatting strings defined in the C99 standard. */
-//# define UINT32PF "%" PRIu32
-//# define UINT64PF "%" PRIu64
-//# define UINT64PFx "%016" PRIx64
-# define UINT32PF "%lu"
+# define UINT32PF "%u"
+#if SIZEOF_LONG == 8
+# define UINT64PF "%lu"
+# define UINT64PFx "%016lx"
+# define UINT64scan "lu"
+#else
# define UINT64PF "%llu"
# define UINT64PFx "%016llx"
+# define UINT64scan "llu"
+#endif
typedef uint64_t ib_uint64_t;
typedef uint32_t ib_uint32_t;
#endif /* _WIN32 */
-/* JAN: TODO: Fix server to use c99 when possible. */
-#define IB_ID_FMT UINT64PF
-
-/* Type used for all log sequence number storage and arithmetics */
-typedef ib_uint64_t lsn_t;
-
#ifdef _WIN64
typedef unsigned __int64 ulint;
typedef __int64 lint;
@@ -542,13 +546,13 @@ typedef long int lint;
#define IB_UINT64_MAX ((ib_uint64_t) (~0ULL))
/** The generic InnoDB system object identifier data type */
-typedef ib_uint64_t ib_id_t;
-#define IB_ID_MAX IB_UINT64_MAX
+typedef ib_uint64_t ib_id_t;
+#define IB_ID_MAX (~(ib_id_t) 0)
+#define IB_ID_FMT UINT64PF
#ifndef UINTMAX_MAX
#define UINTMAX_MAX IB_UINT64_MAX
#endif
-
/** This 'ibool' type is used within Innobase. Remember that different included
headers may define 'bool' differently. Do not assume that 'bool' is a ulint! */
#define ibool ulint
diff --git a/storage/innobase/include/ut0counter.h b/storage/innobase/include/ut0counter.h
index 7c704988139..175427df333 100644
--- a/storage/innobase/include/ut0counter.h
+++ b/storage/innobase/include/ut0counter.h
@@ -34,13 +34,17 @@ Created 2012/04/12 by Sunny Bains
/** CPU cache line size */
#ifndef UNIV_HOTBACKUP
# ifdef CPU_LEVEL1_DCACHE_LINESIZE
-# define CACHE_LINE_SIZE CPU_LEVEL1_DCACHE_LINESIZE
+# define CACHE_LINE_SIZE CPU_LEVEL1_DCACHE_LINESIZE
# else
# error CPU_LEVEL1_DCACHE_LINESIZE is undefined
# endif /* CPU_LEVEL1_DCACHE_LINESIZE */
#else
-# define CACHE_LINE_SIZE 64
+#ifdef powerpc
+#define CACHE_LINE_SIZE 128
+#else
+# define CACHE_LINE_SIZE 64
#endif /* __powerpc__ */
+#endif /* UNIV_HOTBACKUP */
/** Default number of slots to use in ib_counter_t */
#define IB_N_SLOTS 64
diff --git a/storage/innobase/include/ut0crc32.h b/storage/innobase/include/ut0crc32.h
index 2066fa00684..91af6a910ff 100644
--- a/storage/innobase/include/ut0crc32.h
+++ b/storage/innobase/include/ut0crc32.h
@@ -56,6 +56,6 @@ extern ut_crc32_func_t ut_crc32_byte_by_byte;
/** Flag that tells whether the CPU supports CRC32 or not */
extern bool ut_crc32_sse2_enabled;
-extern bool ut_crc32_power8_enabled;
+extern bool ut_crc32_power8_enabled;
#endif /* ut0crc32_h */
diff --git a/storage/innobase/include/ut0dbg.h b/storage/innobase/include/ut0dbg.h
index cf80c1aa0ad..1a61ed84a38 100644
--- a/storage/innobase/include/ut0dbg.h
+++ b/storage/innobase/include/ut0dbg.h
@@ -44,7 +44,7 @@ ut_dbg_assertion_failed(
const char* expr, /*!< in: the failed assertion */
const char* file, /*!< in: source file containing the assertion */
ulint line) /*!< in: line number of the assertion */
- UNIV_COLD MY_ATTRIBUTE((nonnull(2)));
+ UNIV_COLD MY_ATTRIBUTE((nonnull(2), noreturn));
/** Abort execution if EXPR does not evaluate to nonzero.
@param EXPR assertion expression that should hold */
diff --git a/storage/innobase/include/ut0lst.h b/storage/innobase/include/ut0lst.h
index 371e6457a9e..09733da20a0 100644
--- a/storage/innobase/include/ut0lst.h
+++ b/storage/innobase/include/ut0lst.h
@@ -318,7 +318,6 @@ ut_list_insert(
++list.count;
}
-
/*******************************************************************//**
Removes a node from a two-way linked list.
@param list the base node (not a pointer to it)
diff --git a/storage/innobase/include/ut0mem.h b/storage/innobase/include/ut0mem.h
index be7b72b1c19..6d56be4d820 100644
--- a/storage/innobase/include/ut0mem.h
+++ b/storage/innobase/include/ut0mem.h
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/include/ut0new.h b/storage/innobase/include/ut0new.h
index c9e9dcf05f7..6f3c06cf978 100644
--- a/storage/innobase/include/ut0new.h
+++ b/storage/innobase/include/ut0new.h
@@ -227,6 +227,11 @@ struct ut_new_pfx_t {
allocated block and its users are responsible for maintaining it
and passing it later to ut_allocator::deallocate_large(). */
size_t m_size;
+#if SIZEOF_VOIDP == 4
+ /** Pad the header size to a multiple of 64 bits on 32-bit systems,
+ so that the payload will be aligned to 64 bits. */
+ size_t pad;
+#endif
};
/** Allocator class for allocating memory from inside std::* containers. */
@@ -335,6 +340,10 @@ public:
size_t total_bytes = n_elements * sizeof(T);
#ifdef UNIV_PFS_MEMORY
+ /* The header size must not ruin the 64-bit alignment
+ on 32-bit systems. Some allocated structures use
+ 64-bit fields. */
+ ut_ad((sizeof(ut_new_pfx_t) & 7) == 0);
total_bytes += sizeof(ut_new_pfx_t);
#endif /* UNIV_PFS_MEMORY */
@@ -398,7 +407,7 @@ public:
free(pfx);
#else
- free(ptr);
+ // free(ptr);
#endif /* UNIV_PFS_MEMORY */
}
diff --git a/storage/innobase/include/ut0rnd.h b/storage/innobase/include/ut0rnd.h
index 09e66034c4f..aa5b4b6745d 100644
--- a/storage/innobase/include/ut0rnd.h
+++ b/storage/innobase/include/ut0rnd.h
@@ -99,7 +99,7 @@ ulint
ut_fold_string(
/*===========*/
const char* str) /*!< in: null-terminated string */
- MY_ATTRIBUTE((warn_unused_result, pure));
+ MY_ATTRIBUTE((warn_unused_result));
/***********************************************************//**
Looks for a prime number slightly greater than the given argument.
The prime is chosen so that it is not near any power of 2.
diff --git a/storage/innobase/include/ut0rnd.ic b/storage/innobase/include/ut0rnd.ic
index 8abf775869c..503c9482ea3 100644
--- a/storage/innobase/include/ut0rnd.ic
+++ b/storage/innobase/include/ut0rnd.ic
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2013, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/include/ut0ut.h b/storage/innobase/include/ut0ut.h
index f36cd367270..5a1c3989f4d 100644
--- a/storage/innobase/include/ut0ut.h
+++ b/storage/innobase/include/ut0ut.h
@@ -172,7 +172,7 @@ ut_pair_cmp(
ulint a_l,
ulint b_h,
ulint b_l)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/*************************************************************//**
Calculates fast the remainder of n/m when m is a power of two.
@@ -345,7 +345,7 @@ ut_get_year_month_day(
Runs an idle loop on CPU. The argument gives the desired delay
in microseconds on 100 MHz Pentium + Visual C++.
@return dummy value */
-void
+ulint
ut_delay(
/*=====*/
ulint delay); /*!< in: delay in microseconds on 100 MHz Pentium */
@@ -367,7 +367,7 @@ ut_print_buf_hex(
std::ostream& o, /*!< in/out: output stream */
const void* buf, /*!< in: memory buffer */
ulint len) /*!< in: length of the buffer */
- __attribute__((nonnull));
+ MY_ATTRIBUTE((nonnull));
/*************************************************************//**
Prints the contents of a memory buffer in hex and ascii. */
void
@@ -376,7 +376,7 @@ ut_print_buf(
std::ostream& o, /*!< in/out: output stream */
const void* buf, /*!< in: memory buffer */
ulint len) /*!< in: length of the buffer */
- __attribute__((nonnull));
+ MY_ATTRIBUTE((nonnull));
#ifndef UNIV_HOTBACKUP
/* Forward declaration of transaction handle */
@@ -403,26 +403,17 @@ as in SQL database_name.identifier. */
void
ut_print_name(
/*==========*/
- FILE* f, /*!< in: output stream */
+ FILE* ef, /*!< in: stream */
const trx_t* trx, /*!< in: transaction */
const char* name); /*!< in: table name to print */
-/**********************************************************************//**
-Outputs a fixed-length string, quoted as an SQL identifier.
-If the string contains a slash '/', the string will be
-output as two identifiers separated by a period (.),
-as in SQL database_name.identifier. */
-UNIV_INTERN
-std::string
-ut_get_name(
-/*=========*/
- const trx_t* trx, /*!< in: transaction (NULL=no quotes) */
- ibool table_id,/*!< in: TRUE=print a table name,
- FALSE=print other identifier */
- const char* name); /*!< in: name to print */
-/**********************************************************************//**
-Formats a table or index name, quoted as an SQL identifier. If the name
-contains a slash '/', the result will contain two identifiers separated by
-a period (.), as in SQL database_name.identifier.
+/** Format a table name, quoted as an SQL identifier.
+If the name contains a slash '/', the result will contain two
+identifiers separated by a period (.), as in SQL
+database_name.table_name.
+@see table_name_t
+@param[in] name table or index name
+@param[out] formatted formatted result, will be NUL-terminated
+@param[in] formatted_size size of the buffer in bytes
@return pointer to 'formatted' */
char*
ut_format_name(
diff --git a/storage/innobase/include/ut0wqueue.h b/storage/innobase/include/ut0wqueue.h
index 0cc284f7e0d..771d8d6ae5c 100644
--- a/storage/innobase/include/ut0wqueue.h
+++ b/storage/innobase/include/ut0wqueue.h
@@ -96,7 +96,6 @@ void*
ib_wqueue_nowait(
/*=============*/
ib_wqueue_t* wq); /*<! in: work queue */
-
/********************************************************************
Get number of items on queue.
@return number of items on queue */
diff --git a/storage/innobase/innodb.cmake b/storage/innobase/innodb.cmake
index 809e58941e9..c016f536a67 100644
--- a/storage/innobase/innodb.cmake
+++ b/storage/innobase/innodb.cmake
@@ -1,4 +1,4 @@
-# Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+# Copyright (c) 2006, 2016, Oracle and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -18,12 +18,38 @@
INCLUDE(CheckFunctionExists)
INCLUDE(CheckCSourceCompiles)
INCLUDE(CheckCSourceRuns)
-
-IF(LZ4_INCLUDE_DIR AND LZ4_LIBRARY)
- ADD_DEFINITIONS(-DHAVE_LZ4=1)
- INCLUDE_DIRECTORIES(${LZ4_INCLUDE_DIR})
+INCLUDE(lz4)
+INCLUDE(lzo)
+INCLUDE(lzma)
+INCLUDE(bzip2)
+INCLUDE(snappy)
+
+MYSQL_CHECK_LZ4()
+MYSQL_CHECK_LZO()
+MYSQL_CHECK_LZMA()
+MYSQL_CHECK_BZIP2()
+MYSQL_CHECK_SNAPPY()
+
+IF(CMAKE_CROSSCOMPILING)
+ # Use CHECK_C_SOURCE_COMPILES instead of CHECK_C_SOURCE_RUNS when
+ # cross-compiling. Not as precise, but usually good enough.
+ # This only make sense for atomic tests in this file, this trick doesn't
+ # work in a general case.
+ MACRO(CHECK_C_SOURCE SOURCE VAR)
+ CHECK_C_SOURCE_COMPILES("${SOURCE}" "${VAR}")
+ ENDMACRO()
+ELSE()
+ MACRO(CHECK_C_SOURCE SOURCE VAR)
+ CHECK_C_SOURCE_RUNS("${SOURCE}" "${VAR}")
+ ENDMACRO()
ENDIF()
+## MySQL 5.7 LZ4 (not needed)
+##IF(LZ4_INCLUDE_DIR AND LZ4_LIBRARY)
+## ADD_DEFINITIONS(-DHAVE_LZ4=1)
+## INCLUDE_DIRECTORIES(${LZ4_INCLUDE_DIR})
+##ENDIF()
+
# OS tests
IF(UNIX)
IF(CMAKE_SYSTEM_NAME STREQUAL "Linux")
@@ -37,11 +63,13 @@ IF(UNIX)
ADD_DEFINITIONS(-DLINUX_NATIVE_AIO=1)
LINK_LIBRARIES(aio)
ENDIF()
-
IF(HAVE_LIBNUMA)
LINK_LIBRARIES(numa)
ENDIF()
-
+ ELSEIF(CMAKE_SYSTEM_NAME MATCHES "HP*")
+ ADD_DEFINITIONS("-DUNIV_HPUX")
+ ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "AIX")
+ ADD_DEFINITIONS("-DUNIV_AIX")
ELSEIF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
ADD_DEFINITIONS("-DUNIV_SOLARIS")
ENDIF()
@@ -79,7 +107,7 @@ IF(CMAKE_CXX_COMPILER_ID MATCHES "GNU")
ENDIF()
# Enable InnoDB's UNIV_DEBUG in debug builds
-SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DUNIV_DEBUG")
+SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -DUNIV_DEBUG -DUNIV_SYNC_DEBUG")
OPTION(WITH_INNODB_EXTRA_DEBUG "Enable extra InnoDB debug checks" OFF)
IF(WITH_INNODB_EXTRA_DEBUG)
@@ -131,8 +159,81 @@ ENDIF()
IF(NOT MSVC)
# either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
-IF(NOT CMAKE_CROSSCOMPILING)
- CHECK_C_SOURCE_RUNS(
+ # either define HAVE_IB_GCC_ATOMIC_BUILTINS or not
+ # workaround for gcc 4.1.2 RHEL5/x86, gcc atomic ops only work under -march=i686
+ IF(CMAKE_SYSTEM_PROCESSOR STREQUAL "i686" AND CMAKE_COMPILER_IS_GNUCC AND
+ CMAKE_C_COMPILER_VERSION VERSION_LESS "4.1.3")
+ SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i686")
+ SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i686")
+ ENDIF()
+ CHECK_C_SOURCE(
+ "
+ int main()
+ {
+ long x;
+ long y;
+ long res;
+
+ x = 10;
+ y = 123;
+ res = __sync_bool_compare_and_swap(&x, x, y);
+ if (!res || x != y) {
+ return(1);
+ }
+
+ x = 10;
+ y = 123;
+ res = __sync_bool_compare_and_swap(&x, x + 1, y);
+ if (res || x != 10) {
+ return(1);
+ }
+ x = 10;
+ y = 123;
+ res = __sync_add_and_fetch(&x, y);
+ if (res != 123 + 10 || x != 123 + 10) {
+ return(1);
+ }
+ return(0);
+ }"
+ HAVE_IB_GCC_ATOMIC_BUILTINS
+ )
+ CHECK_C_SOURCE(
+ "
+ int main()
+ {
+ long res;
+ char c;
+
+ c = 10;
+ res = __sync_lock_test_and_set(&c, 123);
+ if (res != 10 || c != 123) {
+ return(1);
+ }
+ return(0);
+ }"
+ HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE
+ )
+ CHECK_C_SOURCE(
+ "#include<stdint.h>
+ int main()
+ {
+ int64_t x,y,res;
+
+ x = 10;
+ y = 123;
+ res = __sync_sub_and_fetch(&y, x);
+ if (res != y || y != 113) {
+ return(1);
+ }
+ res = __sync_add_and_fetch(&y, x);
+ if (res != y || y != 123) {
+ return(1);
+ }
+ return(0);
+ }"
+ HAVE_IB_GCC_ATOMIC_BUILTINS_64
+ )
+ CHECK_C_SOURCE(
"#include<stdint.h>
int main()
{
@@ -141,7 +242,7 @@ IF(NOT CMAKE_CROSSCOMPILING)
}"
HAVE_IB_GCC_SYNC_SYNCHRONISE
)
- CHECK_C_SOURCE_RUNS(
+ CHECK_C_SOURCE(
"#include<stdint.h>
int main()
{
@@ -151,6 +252,18 @@ IF(NOT CMAKE_CROSSCOMPILING)
}"
HAVE_IB_GCC_ATOMIC_THREAD_FENCE
)
+ CHECK_C_SOURCE(
+ "#include<stdint.h>
+ int main()
+ {
+ unsigned char c;
+
+ __atomic_test_and_set(&c, __ATOMIC_ACQUIRE);
+ __atomic_clear(&c, __ATOMIC_RELEASE);
+ return(0);
+ }"
+ HAVE_IB_GCC_ATOMIC_TEST_AND_SET
+ )
CHECK_C_SOURCE_RUNS(
"#include<stdint.h>
int main()
@@ -166,6 +279,35 @@ IF(NOT CMAKE_CROSSCOMPILING)
}"
HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE
)
+CHECK_C_SOURCE_RUNS(
+ "#include<stdint.h>
+ int main()
+ {
+ unsigned char a = 0;
+ unsigned char b = 0;
+ unsigned char c = 1;
+
+ __atomic_compare_exchange_n(&a, &b, &c, 0,
+ __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
+ return (0);
+ }"
+ HAVE_IB_GCC_ATOMIC_SEQ_CST
+ )
+
+IF (HAVE_IB_GCC_ATOMIC_SEQ_CST)
+ ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_CST=1)
+ENDIF()
+
+IF(HAVE_IB_GCC_ATOMIC_BUILTINS)
+ ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS=1)
+ENDIF()
+
+IF(HAVE_IB_GCC_ATOMIC_BUILTINS_BYTE)
+ ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_BYTE=1)
+ENDIF()
+
+IF(HAVE_IB_GCC_ATOMIC_BUILTINS_64)
+ ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_BUILTINS_64=1)
ENDIF()
IF(HAVE_IB_GCC_SYNC_SYNCHRONISE)
@@ -176,6 +318,10 @@ IF(HAVE_IB_GCC_ATOMIC_THREAD_FENCE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_THREAD_FENCE=1)
ENDIF()
+IF(HAVE_IB_GCC_ATOMIC_TEST_AND_SET)
+ ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_TEST_AND_SET=1)
+ENDIF()
+
IF(HAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE)
ADD_DEFINITIONS(-DHAVE_IB_GCC_ATOMIC_COMPARE_EXCHANGE=1)
ENDIF()
@@ -202,6 +348,7 @@ IF(NOT CMAKE_CROSSCOMPILING)
}"
HAVE_IB_ATOMIC_PTHREAD_T_GCC)
ENDIF()
+
IF(HAVE_IB_ATOMIC_PTHREAD_T_GCC)
ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_GCC=1)
ENDIF()
@@ -240,6 +387,7 @@ IF(NOT MSVC AND NOT CMAKE_CROSSCOMPILING)
}"
HAVE_IB_LINUX_FUTEX)
ENDIF()
+
IF(HAVE_IB_LINUX_FUTEX)
ADD_DEFINITIONS(-DHAVE_IB_LINUX_FUTEX=1)
ENDIF()
@@ -249,9 +397,60 @@ ENDIF(NOT MSVC)
CHECK_FUNCTION_EXISTS(asprintf HAVE_ASPRINTF)
CHECK_FUNCTION_EXISTS(vasprintf HAVE_VASPRINTF)
+CHECK_CXX_SOURCE_COMPILES("struct t1{ int a; char *b; }; struct t1 c= { .a=1, .b=0 }; main() { }" HAVE_C99_INITIALIZERS)
+IF(HAVE_C99_INITIALIZERS)
+ ADD_DEFINITIONS(-DHAVE_C99_INITIALIZERS)
+ENDIF()
+
# Solaris atomics
IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
- IF(NOT CMAKE_CROSSCOMPILING)
+ CHECK_FUNCTION_EXISTS(atomic_cas_ulong HAVE_ATOMIC_CAS_ULONG)
+ CHECK_FUNCTION_EXISTS(atomic_cas_32 HAVE_ATOMIC_CAS_32)
+ CHECK_FUNCTION_EXISTS(atomic_cas_64 HAVE_ATOMIC_CAS_64)
+ CHECK_FUNCTION_EXISTS(atomic_add_long_nv HAVE_ATOMIC_ADD_LONG_NV)
+ CHECK_FUNCTION_EXISTS(atomic_swap_uchar HAVE_ATOMIC_SWAP_UCHAR)
+ IF(HAVE_ATOMIC_CAS_ULONG AND
+ HAVE_ATOMIC_CAS_32 AND
+ HAVE_ATOMIC_CAS_64 AND
+ HAVE_ATOMIC_ADD_LONG_NV AND
+ HAVE_ATOMIC_SWAP_UCHAR)
+ SET(HAVE_IB_SOLARIS_ATOMICS 1)
+ ENDIF()
+
+ IF(HAVE_IB_SOLARIS_ATOMICS)
+ ADD_DEFINITIONS(-DHAVE_IB_SOLARIS_ATOMICS=1)
+ ENDIF()
+
+ # either define HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS or not
+ CHECK_C_SOURCE_COMPILES(
+ " #include <pthread.h>
+ #include <string.h>
+
+ int main(int argc, char** argv) {
+ pthread_t x1;
+ pthread_t x2;
+ pthread_t x3;
+
+ memset(&x1, 0x0, sizeof(x1));
+ memset(&x2, 0x0, sizeof(x2));
+ memset(&x3, 0x0, sizeof(x3));
+
+ if (sizeof(pthread_t) == 4) {
+
+ atomic_cas_32(&x1, x2, x3);
+
+ } else if (sizeof(pthread_t) == 8) {
+
+ atomic_cas_64(&x1, x2, x3);
+
+ } else {
+
+ return(1);
+ }
+
+ return(0);
+ }
+ " HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
CHECK_C_SOURCE_COMPILES(
"#include <mbarrier.h>
int main() {
@@ -260,16 +459,35 @@ IF(CMAKE_SYSTEM_NAME STREQUAL "SunOS")
return(0);
}"
HAVE_IB_MACHINE_BARRIER_SOLARIS)
+
+ IF(HAVE_IB_ATOMIC_PTHREAD_T_SOLARIS)
+ ADD_DEFINITIONS(-DHAVE_IB_ATOMIC_PTHREAD_T_SOLARIS=1)
ENDIF()
IF(HAVE_IB_MACHINE_BARRIER_SOLARIS)
ADD_DEFINITIONS(-DHAVE_IB_MACHINE_BARRIER_SOLARIS=1)
ENDIF()
ENDIF()
+
+IF(UNIX)
+# this is needed to know which one of atomic_cas_32() or atomic_cas_64()
+# to use in the source
+SET(CMAKE_EXTRA_INCLUDE_FILES pthread.h)
+CHECK_TYPE_SIZE(pthread_t SIZEOF_PTHREAD_T)
+SET(CMAKE_EXTRA_INCLUDE_FILES)
+ENDIF()
+
+IF(SIZEOF_PTHREAD_T)
+ ADD_DEFINITIONS(-DSIZEOF_PTHREAD_T=${SIZEOF_PTHREAD_T})
+ENDIF()
+
IF(MSVC)
+ ADD_DEFINITIONS(-DHAVE_WINDOWS_ATOMICS)
ADD_DEFINITIONS(-DHAVE_WINDOWS_MM_FENCE)
ENDIF()
+SET(MUTEXTYPE "event" CACHE STRING "Mutex type: event, sys or futex")
+
IF(MUTEXTYPE MATCHES "event")
ADD_DEFINITIONS(-DMUTEX_EVENT)
ELSEIF(MUTEXTYPE MATCHES "futex" AND DEFINED HAVE_IB_LINUX_FUTEX)
@@ -277,7 +495,37 @@ ELSEIF(MUTEXTYPE MATCHES "futex" AND DEFINED HAVE_IB_LINUX_FUTEX)
ELSE()
ADD_DEFINITIONS(-DMUTEX_SYS)
ENDIF()
+
+# Include directories under innobase
+INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include
+ ${CMAKE_SOURCE_DIR}/storage/innobase/handler)
+
+# Sun Studio bug with -xO2
+IF(CMAKE_CXX_COMPILER_ID MATCHES "SunPro"
+ AND CMAKE_CXX_FLAGS_RELEASE MATCHES "O2"
+ AND NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ # Sun Studio 12 crashes with -xO2 flag, but not with higher optimization
+ # -xO3
+ SET_SOURCE_FILES_PROPERTIES(${CMAKE_CURRENT_SOURCE_DIR}/rem/rem0rec.cc
+ PROPERTIES COMPILE_FLAGS -xO3)
+ENDIF()
+
+# Removing compiler optimizations for innodb/mem/* files on 64-bit Windows
+# due to 64-bit compiler error, See MySQL Bug #19424, #36366, #34297
+IF (MSVC AND CMAKE_SIZEOF_VOID_P EQUAL 8)
+ SET_SOURCE_FILES_PROPERTIES(mem/mem0mem.cc mem/mem0pool.cc
+ PROPERTIES COMPILE_FLAGS -Od)
+ENDIF()
+IF(MSVC)
+ # Avoid "unreferenced label" warning in generated file
+ GET_FILENAME_COMPONENT(_SRC_DIR ${CMAKE_CURRENT_LIST_FILE} PATH)
+ SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/pars0grm.c
+ PROPERTIES COMPILE_FLAGS "/wd4102")
+ SET_SOURCE_FILES_PROPERTIES(${_SRC_DIR}/pars/lexyy.c
+ PROPERTIES COMPILE_FLAGS "/wd4003")
+ENDIF()
+
# Include directories under innobase
INCLUDE_DIRECTORIES(${CMAKE_SOURCE_DIR}/storage/innobase/include
${CMAKE_SOURCE_DIR}/storage/innobase/handler
diff --git a/storage/innobase/lock/lock0lock.cc b/storage/innobase/lock/lock0lock.cc
index fea9d42f25c..b4851ede4ba 100644
--- a/storage/innobase/lock/lock0lock.cc
+++ b/storage/innobase/lock/lock0lock.cc
@@ -26,9 +26,14 @@ Created 5/7/1996 Heikki Tuuri
#define LOCK_MODULE_IMPLEMENTATION
-//#include <mysql/service_thd_engine_lock.h>
+
#include "ha_prototypes.h"
+#ifdef MYSQL_SERVICE_THD_ENGINE_LOCK
+#include <mysql/service_thd_engine_lock.h>
+#endif
+#include <mysql/service_thd_error_context.h>
+
#include "lock0lock.h"
#include "lock0priv.h"
@@ -46,10 +51,15 @@ Created 5/7/1996 Heikki Tuuri
#include "btr0btr.h"
#include "dict0boot.h"
#include "ut0new.h"
+#include "row0sel.h"
+#include "row0mysql.h"
+#include "pars0pars.h"
#include <set>
+#ifdef WITH_WSREP
#include "wsrep_thd.h"
+#endif /* WITH_WSREP */
/** Total number of cached record locks */
static const ulint REC_LOCK_CACHE = 8;
@@ -70,6 +80,10 @@ struct thd_wait_reports {
trx_t *waitees[64]; /*!< Trxs for thd_report_wait_for() */
};
+extern "C" void thd_report_wait_for(MYSQL_THD thd, MYSQL_THD other_thd);
+extern "C" int thd_need_wait_for(const MYSQL_THD thd);
+extern "C" int thd_need_ordering_with(const MYSQL_THD thd, const MYSQL_THD other_thd);
+
/** Deadlock checker. */
class DeadlockChecker {
public:
@@ -297,7 +311,7 @@ ibool
lock_rec_validate_page(
/*===================*/
const buf_block_t* block) /*!< in: buffer block */
- MY_ATTRIBUTE((nonnull, warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* UNIV_DEBUG */
/* The lock system */
@@ -336,7 +350,7 @@ Checks that a transaction id is sensible, i.e., not in the future.
#ifdef UNIV_DEBUG
#else
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
#endif
bool
lock_check_trx_id_sanity(
@@ -410,7 +424,6 @@ lock_sec_rec_cons_read_sees(
should be read or passed over
by a read cursor */
const dict_index_t* index, /*!< in: index */
- const ulint* offsets,/*!< in: rec_get_offsets(rec, index) */
const ReadView* view) /*!< in: consistent read view */
{
ut_ad(page_rec_is_user_rec(rec));
@@ -469,7 +482,7 @@ lock_sys_create(
lock_sys->prdt_page_hash = hash_create(n_cells);
if (!srv_read_only_mode) {
- lock_latest_err_file = os_file_create_tmpfile();
+ lock_latest_err_file = os_file_create_tmpfile(NULL);
ut_a(lock_latest_err_file);
}
}
@@ -921,6 +934,10 @@ lock_rec_has_to_wait(
ib::info() <<
"BF-BF lock conflict, locking: " << for_locking;
lock_rec_print(stderr, lock2);
+ ib::info() << " SQL1: "
+ << wsrep_thd_query(trx->mysql_thd);
+ ib::info() << " SQL2: "
+ << wsrep_thd_query(lock2->trx->mysql_thd);
}
if (wsrep_trx_order_before(trx->mysql_thd,
@@ -940,6 +957,10 @@ lock_rec_has_to_wait(
<< " locked "
<< wsrep_thd_conflict_state(lock2->trx->mysql_thd, FALSE);
lock_rec_print(stderr, lock2);
+ ib::info() << " SQL1: "
+ << wsrep_thd_query(trx->mysql_thd);
+ ib::info() << " SQL2: "
+ << wsrep_thd_query(lock2->trx->mysql_thd);
if (for_locking) {
return FALSE;
@@ -958,11 +979,16 @@ lock_rec_has_to_wait(
<< " table: " << lock2->index->table->name.m_name
<< " n_uniq: " << lock2->index->n_uniq
<< " n_user: " << lock2->index->n_user_defined_cols;
+ ib::info() << " SQL1: "
+ << wsrep_thd_query(trx->mysql_thd);
+ ib::info() << " SQL2: "
+ << wsrep_thd_query(lock2->trx->mysql_thd);
}
return FALSE;
}
}
#endif /* WITH_WSREP */
+
return(TRUE);
}
@@ -999,8 +1025,8 @@ lock_has_to_wait(
lock_get_prdt_from_lock(lock1),
lock2));
} else {
- return(lock_rec_has_to_wait(
- false, lock1->trx, lock1->type_mode, lock2,
+ return(lock_rec_has_to_wait(false,
+ lock1->trx, lock1->type_mode, lock2,
lock_rec_get_nth_bit(lock1, true)));
}
}
@@ -1335,6 +1361,11 @@ wsrep_kill_victim(
} else {
lock_table_print(stderr, lock);
}
+
+ ib::info() << " SQL1: "
+ << wsrep_thd_query(trx->mysql_thd);
+ ib::info() << " SQL2: "
+ << wsrep_thd_query(lock->trx->mysql_thd);
}
lock->trx->abort_type = TRX_WSREP_ABORT;
@@ -1542,6 +1573,8 @@ wsrep_print_wait_locks(
{
if (wsrep_debug && c_lock->trx->lock.wait_lock != c_lock) {
ib::info() << "WSREP: c_lock != wait lock";
+ ib::info() << " SQL: "
+ << wsrep_thd_query(c_lock->trx->mysql_thd);
if (lock_get_type_low(c_lock) & LOCK_TABLE) {
lock_table_print(stderr, c_lock);
@@ -1562,6 +1595,9 @@ wsrep_print_wait_locks(
Check of the lock is on m_rec_id.
@param[in] lock Lock to compare with
@return true if the record lock is on m_rec_id*/
+/**
+@param[in] rhs Lock to compare with
+@return true if the record lock equals rhs */
bool
RecLock::is_on_row(const lock_t* lock) const
{
@@ -1708,15 +1744,21 @@ RecLock::lock_add(lock_t* lock, bool add_to_hash)
Create a new lock.
@param[in,out] trx Transaction requesting the lock
@param[in] owns_trx_mutex true if caller owns the trx_t::mutex
+@param[in] add_to_hash add the lock to hash table
@param[in] prdt Predicate lock (optional)
@return a new lock instance */
lock_t*
-RecLock::create(trx_t* trx, bool owns_trx_mutex, const lock_prdt_t* prdt)
+RecLock::create(trx_t* trx, bool owns_trx_mutex, bool add_to_hash, const lock_prdt_t* prdt)
{
- return create(NULL, trx,owns_trx_mutex, prdt);
+ return create(NULL, trx, owns_trx_mutex, add_to_hash, prdt);
}
lock_t*
-RecLock::create(lock_t* const c_lock, trx_t* trx, bool owns_trx_mutex, const lock_prdt_t* prdt)
+RecLock::create(
+ lock_t* const c_lock,
+ trx_t* trx,
+ bool owns_trx_mutex,
+ bool add_to_hash,
+ const lock_prdt_t* prdt)
{
ut_ad(lock_mutex_own());
ut_ad(owns_trx_mutex == trx_mutex_own(trx));
@@ -1802,16 +1844,20 @@ RecLock::create(lock_t* const c_lock, trx_t* trx, bool owns_trx_mutex, const loc
if (wsrep_debug) {
ib::info() << "WSREP: c_lock canceled " << c_lock->trx->id;
+ ib::info() << " SQL1: "
+ << wsrep_thd_query(c_lock->trx->mysql_thd);
+ ib::info() << " SQL2: "
+ << wsrep_thd_query(trx->mysql_thd);
}
++lock->index->table->n_rec_locks;
/* have to bail out here to avoid lock_set_lock... */
return(lock);
}
- trx_mutex_exit(c_lock->trx);
- /* we don't want to add to hash anymore, but need other updates from lock_add */
+ trx_mutex_exit(c_lock->trx);
+ /* we don't want to add to hash anymore, but need other updates from lock_add */
++lock->index->table->n_rec_locks;
- lock_add(lock, false);
+ lock_add(lock, false);
} else {
#endif /* WITH_WSREP */
@@ -1823,7 +1869,7 @@ RecLock::create(lock_t* const c_lock, trx_t* trx, bool owns_trx_mutex, const loc
trx_mutex_enter(trx);
}
- lock_add(lock, true);
+ lock_add(lock, add_to_hash);
if (!owns_trx_mutex) {
trx_mutex_exit(trx);
@@ -1884,6 +1930,8 @@ RecLock::deadlock_check(lock_t* lock)
ut_ad(lock->trx == m_trx);
ut_ad(trx_mutex_own(m_trx));
+ bool async_rollback = m_trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC;
+
/* This is safe, because DeadlockChecker::check_and_resolve()
is invoked when a lock wait is enqueued for the currently
running transaction. Because m_trx is a running transaction
@@ -1893,9 +1941,12 @@ RecLock::deadlock_check(lock_t* lock)
trx_mutex_exit(m_trx);
- const trx_t* victim_trx;
+ /* If transaction is marked for ASYNC rollback then we should
+ not allow it to wait for another lock causing possible deadlock.
+ We return current transaction as deadlock victim here. */
- victim_trx = DeadlockChecker::check_and_resolve(lock, m_trx);
+ const trx_t* victim_trx = async_rollback ? m_trx
+ : DeadlockChecker::check_and_resolve(lock, m_trx);
trx_mutex_enter(m_trx);
@@ -1916,26 +1967,6 @@ RecLock::deadlock_check(lock_t* lock)
}
/**
-Rollback the transaction that is blocking the requesting transaction
-@param[in, out] lock The blocking lock */
-void
-RecLock::rollback_blocking_trx(lock_t* lock) const
-{
- ut_ad(lock_mutex_own());
- ut_ad(m_trx != lock->trx);
- ut_ad(!trx_mutex_own(m_trx));
- ut_ad(lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT);
-
- ib::info() << "Blocking transaction wake up: ID: " << lock->trx->id;
- lock->trx->lock.was_chosen_as_deadlock_victim = true;
-
- /* Remove the blocking transaction from the hit list. */
- m_trx->hit_list.remove(hit_list_t::value_type(lock->trx));
-
- lock_cancel_waiting_and_release(lock);
-}
-
-/**
Collect the transactions that will need to be rolled back asynchronously
@param[in, out] trx Transaction to be rolled back */
void
@@ -1964,111 +1995,18 @@ RecLock::mark_trx_for_rollback(trx_t* trx)
m_trx->hit_list.push_back(hit_list_t::value_type(trx));
+#ifdef UNIV_DEBUG
THD* thd = trx->mysql_thd;
if (thd != NULL) {
char buffer[1024];
-
ib::info() << "Blocking transaction: ID: " << trx->id << " - "
<< " Blocked transaction ID: "<< m_trx->id << " - "
- << thd_get_error_context_description(thd,
- buffer, sizeof(buffer), 512);
- // JAN: TODO: MySQL 5.7
- // << thd_security_context(thd, buffer, sizeof(buffer),
- // 512);
- }
-}
-
-/**
-Add the lock to the head of the record lock {space, page_no} wait queue and
-the transaction's lock list. If the transactions holding blocking locks are
-already marked for termination then they are not added to the hit list.
-
-@param[in, out] lock Lock being requested
-@param[in, out] wait_for The blocking lock
-@param[in] kill_trx true if the transaction that m_trx is waiting
- for should be killed */
-void
-RecLock::jump_queue(lock_t* lock, const lock_t* wait_for, bool kill_trx)
-{
- ut_ad(m_trx == lock->trx);
- ut_ad(trx_mutex_own(m_trx));
- ut_ad(wait_for->trx != m_trx);
- // JAN: TODO: trx priority
- // ut_ad(trx_is_high_priority(m_trx));
- ut_ad(m_rec_id.m_heap_no != ULINT32_UNDEFINED);
-
- /* We need to change the hash bucket list pointers only. */
-
- lock_t* head = const_cast<lock_t*>(wait_for);
-
- /* If it is already marked for asynchronous rollback, we don't
- roll it back */
-
- if (kill_trx && !wait_for->trx->abort) {
-
- mark_trx_for_rollback(wait_for->trx);
- }
-
- /* H -> T => H -> Lock -> T */
- lock->hash = head->hash;
- head->hash = lock;
-
- ++lock->index->table->n_rec_locks;
-
- typedef std::set<trx_t*> Trxs;
-
- Trxs trxs;
-
- /* Locks ahead in the queue need to be rolled back */
-
- for (lock_t* next = lock->hash; next != NULL; next = next->hash) {
-
- trx_t* trx = next->trx;
-
- if (!is_on_row(next)
- || (trx->lock.que_state == TRX_QUE_LOCK_WAIT
- && trx->lock.wait_lock == next)
- || trx->read_only
- || trx == lock->trx
- || trx == wait_for->trx) {
-
- continue;
- }
-
- ut_ad(next != lock);
- ut_ad(next != wait_for);
-
- Trxs::iterator it;
-
- /* If the transaction is waiting on some other lock.
- The abort state cannot change while we hold the lock
- sys mutex.
-
- There is one loose end. We are ignoring transactions
- that are marked for abort by some other transaction.
- We have to be careful that the other transaction must
- kill these (skipped) transactions, ie. it cannot be
- interrupted before it acts on the trx_t::hit_list.
-
- If the aborted transactions are not killed the worst
- case should be that the high priority transaction
- ends up waiting, it should not affect correctness. */
-
- trx_mutex_enter(trx);
-
- if (!trx->abort
- && (trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE) == 0
- && (it = trxs.find(trx)) == trxs.end()) {
-
- mark_trx_for_rollback(trx);
-
- trxs.insert(it, trx);
- }
-
- trx_mutex_exit(trx);
+ << thd_get_error_context_description(thd, buffer, sizeof(buffer),
+ 512);
}
+#endif /* UNIV_DEBUG */
}
/**
@@ -2093,138 +2031,6 @@ RecLock::set_wait_state(lock_t* lock)
}
/**
-Enqueue a lock wait for a high priority transaction, jump the record lock
-wait queue and if the transaction at the head of the queue is itself waiting
-roll it back.
-@param[in, out] wait_for The lock that the the joining transaction is
- waiting for
-@return NULL if the lock was granted */
-lock_t*
-RecLock::enqueue_priority(const lock_t* wait_for, const lock_prdt_t* prdt)
-{
-#ifdef WITH_WSREP
- ib::info() << "enqueue_priority called, for: " << wait_for->trx->id;
-#endif /* WITH_WSREP */
- /* Create the explicit lock instance and initialise it. */
-
- lock_t* lock = lock_alloc(m_trx, m_index, m_mode, m_rec_id, m_size);
-
- if (prdt != NULL && (m_mode & LOCK_PREDICATE)) {
-
- lock_prdt_set_prdt(lock, prdt);
- }
-
- trx_mutex_enter(wait_for->trx);
-
-#ifdef UNIV_DEBUG
- ulint version = wait_for->trx->version;
-#endif /* UNIV_DEBUG */
-
- bool read_only = wait_for->trx->read_only;
-
- bool waiting = wait_for->trx->lock.que_state == TRX_QUE_LOCK_WAIT;
-
- /* If the transaction that is blocking m_trx is itself waiting then
- we kill it in this method, unless it is waiting for the same lock
- that m_trx wants. For the latter case we kill it before doing the
- lock wait.
-
- If the transaction is not waiting but is a read-only transaction
- started with START TRANSACTION READ ONLY then we wait for it. */
-
- bool kill_trx;
-
- if (waiting) {
-
- ut_ad(wait_for->trx->lock.wait_lock != NULL);
-
- /* Check if "wait_for" trx is waiting for the same lock
- and we can roll it back asynchronously. */
-
- kill_trx = wait_for->trx->lock.wait_lock != wait_for
- && !read_only
- && !(wait_for->trx->in_innodb
- & TRX_FORCE_ROLLBACK_DISABLE);
-
- } else if (read_only) {
-
- /* Wait for running read-only transactions */
-
- kill_trx = false;
-
- } else {
-
- /* Rollback any running non-ro blocking transactions */
-
- kill_trx = !(wait_for->trx->in_innodb
- & TRX_FORCE_ROLLBACK_DISABLE);
- }
-
- /* Move the lock being requested to the head of
- the wait queue so that if the transaction that
- we are waiting for is rolled back we get dibs
- on the row. */
-
- jump_queue(lock, wait_for, kill_trx);
-
-
- /* Only if the blocking transaction is itself waiting, but
- waiting on a different lock we do the rollback here. For active
- transactions we do the rollback before we enter lock wait. */
-
- if (waiting && kill_trx) {
-
- UT_LIST_ADD_LAST(m_trx->lock.trx_locks, lock);
-
- set_wait_state(lock);
-
- lock_set_lock_and_trx_wait(lock, m_trx);
-
- trx_mutex_exit(m_trx);
-
- /* Rollback the transaction that is blocking us. It should
- be the one that is at the head of the queue. Note this
- doesn't guarantee that our lock will be granted. We will kill
- other blocking transactions later in trx_kill_blocking(). */
-
- rollback_blocking_trx(wait_for->trx->lock.wait_lock);
-
- trx_mutex_exit(wait_for->trx);
-
- /* This state should not change even if we release the
- wait_for->trx->mutex. These can only change if we release
- the lock_sys_t::mutex. */
-
- ut_ad(version == wait_for->trx->version);
- ut_ad(read_only == wait_for->trx->read_only);
-
- trx_mutex_enter(m_trx);
-
- /* There is no guaranteed that the lock will have been granted
- even if we were the first in the queue. There could be other
- transactions that hold e.g., a granted S lock but are waiting
- for another lock. They will be rolled back later. */
-
- return(lock_get_wait(lock) ? lock : NULL);
-
- } else {
-
- trx_mutex_exit(wait_for->trx);
-
- lock_add(lock, false);
- }
-
- /* This state should not change even if we release the
- wait_for->trx->mutex. These can only change if we release
- the lock_sys_t::mutex. */
-
- ut_ad(version == wait_for->trx->version);
- ut_ad(read_only == wait_for->trx->read_only);
-
- return(lock);
-}
-
-/**
Enqueue a lock wait for normal transaction. If it is a high priority transaction
then jump the record lock wait queue and if the transaction at the head of the
queue is itself waiting roll it back, also do a deadlock check and resolve.
@@ -2251,124 +2057,21 @@ RecLock::add_to_waitq(const lock_t* wait_for, const lock_prdt_t* prdt)
prepare();
- lock_t* lock;
- const trx_t* victim_trx;
+ bool high_priority = trx_is_high_priority(m_trx);
- /* We don't rollback internal (basically background statistics
- gathering) transactions. The problem is that we don't currently
- block them using the TrxInInnoDB() mechanism. */
+ /* Don't queue the lock to hash table, if high priority transaction. */
+ lock_t* lock = create(m_trx, true, !high_priority, prdt);
- if (wait_for->trx->mysql_thd == NULL) {
+ /* Attempt to jump over the low priority waiting locks. */
+ if (high_priority && jump_queue(lock, wait_for)) {
- victim_trx = NULL;
-
- } else {
-
- /* Currently, if both are high priority transactions then
- the requesting transaction will be rolled back. */
-
- victim_trx = trx_arbitrate(m_trx, wait_for->trx);
- }
-
- if (victim_trx == m_trx || victim_trx == NULL) {
-
-#ifdef WITH_WSREP
- if (wsrep_on(m_trx->mysql_thd) &&
- m_trx->lock.was_chosen_as_deadlock_victim) {
- return(DB_DEADLOCK);
- }
-#endif /* WITH_WSREP */
-
- /* Ensure that the wait flag is not set. */
- lock = create((lock_t*)wait_for, m_trx, true, prdt);
-
- /* If a high priority transaction has been selected as
- a victim there is nothing we can do. */
-
- if (trx_is_high_priority(m_trx) && victim_trx != NULL) {
-
- lock_reset_lock_and_trx_wait(lock);
-
- lock_rec_reset_nth_bit(lock, m_rec_id.m_heap_no);
-
- if (victim_trx->mysql_thd != NULL) {
- char buffer[1024];
- THD* thd = victim_trx->mysql_thd;
-
- ib::info() << "High priority transaction"
- " selected for rollback : "
- << thd_get_error_context_description(thd,
- buffer, sizeof(buffer), 512);
- /* JAN: TODO: MySQL 5.7
- << thd_security_context(
- thd, buffer, sizeof(buffer),
- 512);
- */
-#ifdef WITH_WSREP
- if (wsrep_on(victim_trx->mysql_thd)) {
- ib::info() << "WSREP seqnos, BF: "
- << wsrep_thd_trx_seqno(
- wait_for->trx->mysql_thd)
- << ", victim: "
- << wsrep_thd_trx_seqno(victim_trx->mysql_thd);
-
- lock_rec_print(stderr, lock);
-
- ulint max_query_len = 1024;
- ulint n_rec_locks =
- lock_number_of_rows_locked(&m_trx->lock);
- ulint n_trx_locks = UT_LIST_GET_LEN(
- m_trx->lock.trx_locks);
- ulint heap_size = mem_heap_get_size(
- m_trx->lock.lock_heap);
-
- mutex_enter(&trx_sys->mutex);
- trx_print_low(stderr, m_trx, max_query_len,
- n_rec_locks, n_trx_locks,
- heap_size);
-
- n_rec_locks = lock_number_of_rows_locked(
- &wait_for->trx->lock);
- n_trx_locks = UT_LIST_GET_LEN(
- wait_for->trx->lock.trx_locks);
- heap_size = mem_heap_get_size(
- wait_for->trx->lock.lock_heap);
-
- trx_print_low(stderr, wait_for->trx,
- max_query_len,
- n_rec_locks, n_trx_locks,
- heap_size);
- mutex_exit(&trx_sys->mutex);
- }
-#endif /* WITH_WSREP */
- }
-
- return(DB_DEADLOCK);
- }
-
- } else if ((lock = enqueue_priority(wait_for, prdt)) == NULL) {
-
- /* Lock was granted */
+ /* Lock is granted */
return(DB_SUCCESS);
}
- dberr_t err = DB_LOCK_WAIT;
+ ut_ad(lock_get_wait(lock));
-#ifdef WITH_WSREP
- if (wsrep_thd_is_BF(m_trx->mysql_thd, FALSE) && !lock_get_wait(lock)) {
- if (wsrep_debug) {
- ib::info() <<
- "BF thread got lock granted early, ID " << lock->trx->id;
- }
- err = DB_SUCCESS;
- } else {
-#endif /* WITH_WSREP */
- ut_ad(lock_get_wait(lock));
-
- err = deadlock_check(lock);
-#ifdef WITH_WSREP
- }
-#endif /* WITH_WSREP */
+ dberr_t err = deadlock_check(lock);
ut_ad(trx_mutex_own(m_trx));
@@ -2440,7 +2143,7 @@ lock_rec_add_to_queue(
wsrep_thd_conflict_state(trx->mysql_thd, false) << " seqno: " <<
wsrep_thd_trx_seqno(trx->mysql_thd) << " SQL: " <<
wsrep_thd_query(trx->mysql_thd);
- trx_t* otrx = other_lock->trx;
+ trx_t* otrx = other_lock->trx;
ib::info() << "WSREP other lock:\n BF:" <<
((wsrep_thd_is_BF(otrx->mysql_thd, FALSE)) ? "BF" : "normal") << " exec: " <<
wsrep_thd_exec_mode(otrx->mysql_thd) << " conflict: " <<
@@ -2506,7 +2209,7 @@ lock_rec_add_to_queue(
RecLock rec_lock(index, block, heap_no, type_mode);
- rec_lock.create(trx, caller_owns_trx_mutex);
+ rec_lock.create(trx, caller_owns_trx_mutex, true);
}
/*********************************************************************//**
@@ -2562,7 +2265,7 @@ lock_rec_lock_fast(
RecLock rec_lock(index, block, heap_no, mode);
/* Note that we don't own the trx mutex. */
- rec_lock.create(trx, false);
+ rec_lock.create(trx, false, true);
}
status = LOCK_REC_SUCCESS_CREATED;
@@ -2796,7 +2499,6 @@ lock_grant(
lock_t* lock) /*!< in/out: waiting lock request */
{
ut_ad(lock_mutex_own());
- ut_ad(!trx_mutex_own(lock->trx));
lock_reset_lock_and_trx_wait(lock);
@@ -2805,22 +2507,18 @@ lock_grant(
if (lock_get_mode(lock) == LOCK_AUTO_INC) {
dict_table_t* table = lock->un_member.tab_lock.table;
- if (UNIV_UNLIKELY(table->autoinc_trx == lock->trx)) {
+ if (table->autoinc_trx == lock->trx) {
ib::error() << "Transaction already had an"
- << " AUTO-INC lock!";
- } else {
+ << " AUTO-INC lock!";
+ } else {
table->autoinc_trx = lock->trx;
ib_vector_push(lock->trx->autoinc_locks, &lock);
}
}
-#ifdef UNIV_DEBUG_NEW
- if (lock_print_waits) {
- fprintf(stderr, "Lock wait for trx " TRX_ID_FMT " ends\n",
- lock->trx->id);
- }
-#endif /* UNIV_DEBUG_NEW */
+ DBUG_PRINT("ib_lock", ("wait for trx " TRX_ID_FMT " ends",
+ trx_get_id_for_print(lock->trx)));
/* If we are resolving a deadlock by choosing another transaction
as a victim, then our original transaction may not be in the
@@ -2837,18 +2535,233 @@ lock_grant(
}
}
- /* Cumulate total lock wait time for statistics */
- if (lock_get_type_low(lock) & LOCK_TABLE) {
- lock->trx->total_table_lock_wait_time +=
- (ulint)difftime(ut_time(), lock->trx->lock.wait_started);
- } else {
- lock->trx->total_rec_lock_wait_time +=
- (ulint)difftime(ut_time(), lock->trx->lock.wait_started);
+ trx_mutex_exit(lock->trx);
+}
+
+/**
+Jump the queue for the record over all low priority transactions and
+add the lock. If all current granted locks are compatible, grant the
+lock. Otherwise, mark all granted transaction for asynchronous
+rollback and add to hit list.
+@param[in, out] lock Lock being requested
+@param[in] conflict_lock First conflicting lock from the head
+@return true if the lock is granted */
+bool
+RecLock::jump_queue(
+ lock_t* lock,
+ const lock_t* conflict_lock)
+{
+ ut_ad(m_trx == lock->trx);
+ ut_ad(trx_mutex_own(m_trx));
+ ut_ad(conflict_lock->trx != m_trx);
+ ut_ad(trx_is_high_priority(m_trx));
+ ut_ad(m_rec_id.m_heap_no != ULINT32_UNDEFINED);
+
+ bool high_priority = false;
+
+ /* Find out the position to add the lock. If there are other high
+ priority transactions in waiting state then we should add it after
+ the last high priority transaction. Otherwise, we can add it after
+ the last granted lock jumping over the wait queue. */
+ bool grant_lock = lock_add_priority(lock, conflict_lock,
+ &high_priority);
+
+ if (grant_lock) {
+
+ ut_ad(conflict_lock->trx->lock.que_state == TRX_QUE_LOCK_WAIT);
+ ut_ad(conflict_lock->trx->lock.wait_lock == conflict_lock);
+
+#ifdef UNIV_DEBUG
+ ib::info() << "Granting High Priority Transaction (ID): "
+ << lock->trx->id << " the lock jumping over"
+ << " waiting Transaction (ID): "
+ << conflict_lock->trx->id;
+#endif /* UNIV_DEBUG */
+
+ lock_reset_lock_and_trx_wait(lock);
+ return(true);
}
- lock->wait_time = (ulint)difftime(ut_time(), lock->requested_time);
+ /* If another high priority transaction is found waiting
+ victim transactions are already marked for rollback. */
+ if (high_priority) {
- trx_mutex_exit(lock->trx);
+ return(false);
+ }
+
+ /* The lock is placed after the last granted lock in the queue. Check and add
+ low priority transactinos to hit list for ASYNC rollback. */
+ make_trx_hit_list(lock, conflict_lock);
+
+ return(false);
+}
+
+/** Find position in lock queue and add the high priority transaction
+lock. Intention and GAP only locks can be granted even if there are
+waiting locks in front of the queue. To add the High priority
+transaction in a safe position we keep the following rule.
+
+1. If the lock can be granted, add it before the first waiting lock
+in the queue so that all currently waiting locks need to do conflict
+check before getting granted.
+
+2. If the lock has to wait, add it after the last granted lock or the
+last waiting high priority transaction in the queue whichever is later.
+This ensures that the transaction is granted only after doing conflict
+check with all granted transactions.
+@param[in] lock Lock being requested
+@param[in] conflict_lock First conflicting lock from the head
+@param[out] high_priority high priority transaction ahead in queue
+@return true if the lock can be granted */
+bool
+RecLock::lock_add_priority(
+ lock_t* lock,
+ const lock_t* conflict_lock,
+ bool* high_priority)
+{
+ ut_ad(high_priority);
+
+ *high_priority = false;
+
+ /* If the first conflicting lock is waiting for the current row,
+ then all other granted locks are compatible and the lock can be
+ directly granted if no other high priority transactions are
+ waiting. We need to recheck with all granted transaction as there
+ could be granted GAP or Intention locks down the queue. */
+ bool grant_lock = (conflict_lock->is_waiting());
+ lock_t* lock_head = NULL;
+ lock_t* grant_position = NULL;
+ lock_t* add_position = NULL;
+
+ HASH_SEARCH(hash, lock_sys->rec_hash, m_rec_id.fold(), lock_t*,
+ lock_head, ut_ad(lock_head->is_record_lock()), true);
+
+ ut_ad(lock_head);
+
+ for (lock_t* next = lock_head; next != NULL; next = next->hash) {
+
+ /* check only for locks on the current row */
+ if (!is_on_row(next)) {
+ continue;
+ }
+
+ if (next->is_waiting()) {
+ /* grant lock position is the granted lock just before
+ the first wait lock in the queue. */
+ if (grant_position == NULL) {
+ grant_position = add_position;
+ }
+
+ if (trx_is_high_priority(next->trx)) {
+
+ *high_priority = true;
+ grant_lock = false;
+ add_position = next;
+ }
+ } else {
+
+ add_position = next;
+ /* Cannot grant lock if there is any conflicting
+ granted lock. */
+ if (grant_lock && lock_has_to_wait(lock, next)) {
+ grant_lock = false;
+ }
+ }
+ }
+
+ /* If the lock is to be granted it is safe to add before the first
+ waiting lock in the queue. */
+ if (grant_lock) {
+
+ ut_ad(!lock_has_to_wait(lock, grant_position));
+ add_position = grant_position;
+ }
+
+ ut_ad(add_position != NULL);
+
+ /* Add the lock to lock hash table. */
+ lock->hash = add_position->hash;
+ add_position->hash = lock;
+ ++lock->index->table->n_rec_locks;
+
+ return(grant_lock);
+}
+
+/** Iterate over the granted locks and prepare the hit list for ASYNC Rollback.
+If the transaction is waiting for some other lock then wake up with deadlock error.
+Currently we don't mark following transactions for ASYNC Rollback.
+1. Read only transactions
+2. Background transactions
+3. Other High priority transactions
+@param[in] lock Lock being requested
+@param[in] conflict_lock First conflicting lock from the head */
+void
+RecLock::make_trx_hit_list(
+ lock_t* lock,
+ const lock_t* conflict_lock)
+{
+ const lock_t* next;
+
+ for (next = conflict_lock; next != NULL; next = next->hash) {
+
+ /* All locks ahead in the queue are checked. */
+ if (next == lock) {
+
+ ut_ad(next->is_waiting());
+ break;
+ }
+
+ trx_t* trx = next->trx;
+ /* Check only for conflicting, granted locks on the current row.
+ Currently, we don't rollback read only transactions, transactions
+ owned by background threads. */
+ if (trx == lock->trx
+ || !is_on_row(next)
+ || next->is_waiting()
+ || trx->read_only
+ || trx->mysql_thd == NULL
+ || !lock_has_to_wait(lock, next)) {
+
+ continue;
+ }
+
+ trx_mutex_enter(trx);
+
+ /* Skip high priority transactions, if already marked for abort
+ by some other transaction or if ASYNC rollback is disabled. A
+ transaction must complete kill/abort of a victim transaction once
+ marked and added to hit list. */
+ if (trx_is_high_priority(trx)
+ || (trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE) != 0
+ || trx->abort) {
+
+ trx_mutex_exit(trx);
+ continue;
+ }
+
+ /* If the transaction is waiting on some other resource then
+ wake it up with DEAD_LOCK error so that it can rollback. */
+ if (trx->lock.que_state == TRX_QUE_LOCK_WAIT) {
+
+ /* Assert that it is not waiting for current record. */
+ ut_ad(trx->lock.wait_lock != next);
+#ifdef UNIV_DEBUG
+ ib::info() << "High Priority Transaction (ID): "
+ << lock->trx->id << " waking up blocking"
+ << " transaction (ID): " << trx->id;
+#endif /* UNIV_DEBUG */
+ trx->lock.was_chosen_as_deadlock_victim = true;
+ lock_cancel_waiting_and_release(trx->lock.wait_lock);
+ trx_mutex_exit(trx);
+ continue;
+ }
+
+ /* Mark for ASYNC Rollback and add to hit list. */
+ mark_trx_for_rollback(trx);
+ trx_mutex_exit(trx);
+ }
+
+ ut_ad(next == lock);
}
/*************************************************************//**
@@ -2941,10 +2854,10 @@ lock_rec_dequeue_from_page(
/* Grant the lock */
ut_ad(lock->trx != in_lock->trx);
+
bool exit_trx_mutex = false;
- if (in_lock->trx->abort_type == TRX_REPLICATION_ABORT &&
- lock->trx->abort_type == TRX_SERVER_ABORT) {
+ if (lock->trx->abort_type != TRX_SERVER_ABORT) {
ut_ad(trx_mutex_own(lock->trx));
trx_mutex_exit(lock->trx);
exit_trx_mutex = true;
@@ -4172,12 +4085,14 @@ lock_table_create(
if (wsrep_debug) {
ib::info() << "table lock BF conflict for " <<
c_lock->trx->id;
+ ib::info() << " SQL: "
+ << wsrep_thd_query(c_lock->trx->mysql_thd);
}
} else {
ut_list_append(table->locks, lock, TableLockGetNode());
}
-
if (c_lock) {
+ ut_ad(!trx_mutex_own(c_lock->trx));
trx_mutex_enter(c_lock->trx);
}
@@ -4206,6 +4121,8 @@ lock_table_create(
if (wsrep_debug) {
ib::info() << "WSREP: c_lock canceled " << c_lock->trx->id;
+ ib::info() << " SQL: "
+ << wsrep_thd_query(c_lock->trx->mysql_thd);
}
}
@@ -4419,16 +4336,16 @@ lock_table_enqueue_waiting(
ut_ad(0);
}
- /* Enqueue the lock request that will wait to be granted */
-
#ifdef WITH_WSREP
if (trx->lock.was_chosen_as_deadlock_victim) {
return(DB_DEADLOCK);
}
#endif /* WITH_WSREP */
+ /* Enqueue the lock request that will wait to be granted */
lock = lock_table_create(c_lock, table, mode | LOCK_WAIT, trx);
+ bool async_rollback = trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC;
/* Release the mutex to obey the latching order.
This is safe, because DeadlockChecker::check_and_resolve()
is invoked when a lock wait is enqueued for the currently
@@ -4439,9 +4356,12 @@ lock_table_enqueue_waiting(
trx_mutex_exit(trx);
- const trx_t* victim_trx;
+ /* If transaction is marked for ASYNC rollback then we should
+ not allow it to wait for another lock causing possible deadlock.
+ We return current transaction as deadlock victim here. */
- victim_trx = DeadlockChecker::check_and_resolve(lock, trx);
+ const trx_t* victim_trx = async_rollback ? trx
+ : DeadlockChecker::check_and_resolve(lock, trx);
trx_mutex_enter(trx);
@@ -4473,17 +4393,6 @@ lock_table_enqueue_waiting(
return(DB_LOCK_WAIT);
}
-static
-dberr_t
-lock_table_enqueue_waiting(
-/*=======================*/
- ulint mode, /*!< in: lock mode this transaction is
- requesting */
- dict_table_t* table, /*!< in/out: table */
- que_thr_t* thr) /*!< in: query thread */
-{
- return (lock_table_enqueue_waiting(NULL, mode, table, thr));
-}
/*********************************************************************//**
Checks if other transactions have an incompatible mode lock request in
@@ -4512,10 +4421,14 @@ lock_table_other_has_incompatible(
if (lock->trx != trx
&& !lock_mode_compatible(lock_get_mode(lock), mode)
&& (wait || !lock_get_wait(lock))) {
+
#ifdef WITH_WSREP
if (wsrep_on(lock->trx->mysql_thd)) {
if (wsrep_debug) {
- ib::info() << "WSREP: table lock abort";
+ ib::info() << "WSREP: table lock abort for table:"
+ << table->name.m_name;
+ ib::info() << " SQL: "
+ << wsrep_thd_query(lock->trx->mysql_thd);
}
trx_mutex_enter(lock->trx);
wsrep_kill_victim((trx_t *)trx, (lock_t *)lock);
@@ -4548,8 +4461,7 @@ lock_table(
dberr_t err;
const lock_t* wait_for;
- ut_ad(table != NULL);
- ut_ad(thr != NULL);
+ ut_ad(table && thr);
/* Given limited visibility of temp-table we can avoid
locking overhead */
@@ -4603,8 +4515,7 @@ lock_table(
mode: this trx may have to wait */
if (wait_for != NULL) {
- err = lock_table_enqueue_waiting((lock_t*)wait_for,
- mode | flags, table, thr);
+ err = lock_table_enqueue_waiting((lock_t*)wait_for, mode | flags, table, thr);
} else {
lock_table_create(table, mode | flags, trx);
@@ -4714,6 +4625,84 @@ lock_table_dequeue(
}
}
+/** Sets a lock on a table based on the given mode.
+@param[in] table table to lock
+@param[in,out] trx transaction
+@param[in] mode LOCK_X or LOCK_S
+@return error code or DB_SUCCESS. */
+dberr_t
+lock_table_for_trx(
+ dict_table_t* table,
+ trx_t* trx,
+ enum lock_mode mode)
+{
+ mem_heap_t* heap;
+ que_thr_t* thr;
+ dberr_t err;
+ sel_node_t* node;
+ heap = mem_heap_create(512);
+
+ node = sel_node_create(heap);
+ thr = pars_complete_graph_for_exec(node, trx, heap, NULL);
+ thr->graph->state = QUE_FORK_ACTIVE;
+
+ /* We use the select query graph as the dummy graph needed
+ in the lock module call */
+
+ thr = static_cast<que_thr_t*>(
+ que_fork_get_first_thr(
+ static_cast<que_fork_t*>(que_node_get_parent(thr))));
+
+ que_thr_move_to_run_state_for_mysql(thr, trx);
+
+run_again:
+ thr->run_node = thr;
+ thr->prev_node = thr->common.parent;
+
+ err = lock_table(0, table, mode, thr);
+
+ trx->error_state = err;
+
+ if (UNIV_LIKELY(err == DB_SUCCESS)) {
+ que_thr_stop_for_mysql_no_error(thr, trx);
+ } else {
+ que_thr_stop_for_mysql(thr);
+
+ if (err != DB_QUE_THR_SUSPENDED) {
+ bool was_lock_wait;
+
+ was_lock_wait = row_mysql_handle_errors(
+ &err, trx, thr, NULL);
+
+ if (was_lock_wait) {
+ goto run_again;
+ }
+ } else {
+ que_thr_t* run_thr;
+ que_node_t* parent;
+
+ parent = que_node_get_parent(thr);
+
+ run_thr = que_fork_start_command(
+ static_cast<que_fork_t*>(parent));
+
+ ut_a(run_thr == thr);
+
+ /* There was a lock wait but the thread was not
+ in a ready to run or running state. */
+ trx->error_state = DB_LOCK_WAIT;
+
+ goto run_again;
+
+ }
+ }
+
+ que_graph_free(thr->graph);
+ trx->op_info = "";
+
+ return(err);
+}
+
/*=========================== LOCK RELEASE ==============================*/
/*************************************************************//**
@@ -5968,13 +5957,13 @@ lock_rec_queue_validate(
wsrep_thd_conflict_state(otrx->mysql_thd, false) << " seqno: " <<
wsrep_thd_trx_seqno(otrx->mysql_thd) << " SQL: " <<
wsrep_thd_query(otrx->mysql_thd);
- }
+ }
if (wsrep_on(other_lock->trx->mysql_thd) && !lock_rec_has_expl(
LOCK_X | LOCK_REC_NOT_GAP,
block, heap_no, impl_trx)) {
ib::info() << "WSREP impl BF lock conflict";
- }
+ }
#else /* !WITH_WSREP */
ut_a(lock_get_wait(other_lock));
ut_a(lock_rec_has_expl(
@@ -6162,7 +6151,7 @@ lock_validate_table_locks(
/*********************************************************************//**
Validate record locks up to a limit.
@return lock at limit or NULL if no more locks in the hash bucket */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
const lock_t*
lock_rec_validate(
/*==============*/
@@ -6227,9 +6216,19 @@ lock_rec_block_validate(
BUF_GET_POSSIBLY_FREED,
__FILE__, __LINE__, &mtr, &err);
- buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
+ if (err != DB_SUCCESS) {
+ ib::error() << "Lock rec block validate failed for tablespace "
+ << ((space && space->name) ? space->name : " system ")
+ << " space_id " << space_id
+ << " page_no " << page_no << " err " << err;
+ }
+
+ if (block) {
+ buf_block_dbg_add_level(block, SYNC_NO_ORDER_CHECK);
+
+ ut_ad(lock_rec_validate_page(block));
+ }
- ut_ad(lock_rec_validate_page(block));
mtr_commit(&mtr);
fil_space_release(space);
@@ -6514,7 +6513,6 @@ lock_rec_convert_impl_to_expl(
LOCK_S | LOCK_REC_NOT_GAP, trx, rec, block));
}
-
if (trx != 0) {
ulint heap_no = page_rec_get_heap_no(rec);
@@ -6572,9 +6570,8 @@ lock_clust_rec_modify_check_and_lock(
lock_rec_convert_impl_to_expl(block, rec, index, offsets);
lock_mutex_enter();
- trx_t* trx __attribute__((unused))= thr_get_trx(thr);
- ut_ad(lock_table_has(trx, index->table, LOCK_IX));
+ ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
block, heap_no, index, thr);
@@ -6633,10 +6630,9 @@ lock_sec_rec_modify_check_and_lock(
index record, and this would not have been possible if another active
transaction had modified this secondary index record. */
- trx_t* trx __attribute__((unused))= thr_get_trx(thr);
lock_mutex_enter();
- ut_ad(lock_table_has(trx, index->table, LOCK_IX));
+ ut_ad(lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
err = lock_rec_lock(TRUE, LOCK_X | LOCK_REC_NOT_GAP,
block, heap_no, index, thr);
@@ -6734,13 +6730,12 @@ lock_sec_rec_read_check_and_lock(
lock_rec_convert_impl_to_expl(block, rec, index, offsets);
}
- trx_t* trx __attribute__((unused))= thr_get_trx(thr);
lock_mutex_enter();
ut_ad(mode != LOCK_X
- || lock_table_has(trx, index->table, LOCK_IX));
+ || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
ut_ad(mode != LOCK_S
- || lock_table_has(trx, index->table, LOCK_IS));
+ || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
err = lock_rec_lock(FALSE, mode | gap_mode,
block, heap_no, index, thr);
@@ -6809,12 +6804,11 @@ lock_clust_rec_read_check_and_lock(
}
lock_mutex_enter();
- trx_t* trx __attribute__((unused))= thr_get_trx(thr);
ut_ad(mode != LOCK_X
- || lock_table_has(trx, index->table, LOCK_IX));
+ || lock_table_has(thr_get_trx(thr), index->table, LOCK_IX));
ut_ad(mode != LOCK_S
- || lock_table_has(trx, index->table, LOCK_IS));
+ || lock_table_has(thr_get_trx(thr), index->table, LOCK_IS));
err = lock_rec_lock(FALSE, mode | gap_mode, block, heap_no, index, thr);
@@ -7250,9 +7244,17 @@ lock_trx_release_locks(
ut_ad(trx_state_eq(trx, TRX_STATE_ACTIVE));
}
- /* The transition of trx->state to TRX_STATE_COMMITTED_IN_MEMORY
- is protected by both the lock_sys->mutex and the trx->mutex. */
- lock_mutex_enter();
+ bool release_lock;
+
+ release_lock = (UT_LIST_GET_LEN(trx->lock.trx_locks) > 0);
+
+ /* Don't take lock_sys mutex if trx didn't acquire any lock. */
+ if (release_lock) {
+
+ /* The transition of trx->state to TRX_STATE_COMMITTED_IN_MEMORY
+ is protected by both the lock_sys->mutex and the trx->mutex. */
+ lock_mutex_enter();
+ }
trx_mutex_enter(trx);
@@ -7276,6 +7278,8 @@ lock_trx_release_locks(
if (trx_is_referenced(trx)) {
+ ut_a(release_lock);
+
lock_mutex_exit();
while (trx_is_referenced(trx)) {
@@ -7315,11 +7319,14 @@ lock_trx_release_locks(
trx_mutex_exit(trx);
- lock_release(trx);
+ if (release_lock) {
- trx->lock.n_rec_locks = 0;
+ lock_release(trx);
- lock_mutex_exit();
+ lock_mutex_exit();
+ }
+
+ trx->lock.n_rec_locks = 0;
/* We don't remove the locks one by one from the vector for
efficiency reasons. We simply reset it because we would have
@@ -7722,7 +7729,7 @@ DeadlockChecker::get_next_lock(const lock_t* lock, ulint heap_no) const
ut_ad(heap_no == ULINT_UNDEFINED);
ut_ad(lock_get_type_low(lock) == LOCK_TABLE);
- lock = UT_LIST_GET_PREV(
+ lock = UT_LIST_GET_NEXT(
un_member.tab_lock.locks, lock);
}
@@ -7785,7 +7792,8 @@ DeadlockChecker::get_first_lock(ulint* heap_no) const
/* Table locks don't care about the heap_no. */
*heap_no = ULINT_UNDEFINED;
ut_ad(lock_get_type_low(lock) == LOCK_TABLE);
- lock = UT_LIST_GET_PREV(un_member.tab_lock.locks, lock);
+ dict_table_t* table = lock->un_member.tab_lock.table;
+ lock = UT_LIST_GET_FIRST(table->locks);
}
/* Must find at least two locks, otherwise there cannot be a
@@ -7951,25 +7959,11 @@ DeadlockChecker::search()
} else if (is_too_deep()) {
- const trx_t* victim_trx;
-
/* Search too deep to continue. */
-
m_too_deep = true;
-
- /* Select the transaction to rollback */
-
- victim_trx = trx_arbitrate(m_start, m_wait_lock->trx);
-
- if (victim_trx == NULL || victim_trx == m_start) {
-
- return(m_start);
- }
-
- return(m_wait_lock->trx);
+ return(m_start);
} else {
-
/* We do not need to report autoinc locks to the upper
layer. These locks are released before commit, so they
can not cause deadlocks with binlog-fixed commit
@@ -7984,13 +7978,16 @@ DeadlockChecker::search()
(struct thd_wait_reports *)
ut_malloc_nokey(sizeof(*m_waitee_ptr));
m_waitee_ptr = m_waitee_ptr->next;
+
if (!m_waitee_ptr) {
m_too_deep = true;
return (m_start);
}
+
m_waitee_ptr->next = NULL;
m_waitee_ptr->used = 0;
}
+
m_waitee_ptr->waitees[m_waitee_ptr->used++] = lock->trx;
}
@@ -8135,6 +8132,7 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, const trx_t* trx)
THD* start_mysql_thd;
start_mysql_thd = trx->mysql_thd;
+
if (start_mysql_thd && thd_need_wait_for(start_mysql_thd)) {
waitee_buf_ptr = &waitee_buf;
} else {
@@ -8143,13 +8141,13 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, const trx_t* trx)
/* Try and resolve as many deadlocks as possible. */
do {
- DeadlockChecker checker(trx, lock, s_lock_mark_counter, waitee_buf_ptr);
-
if (waitee_buf_ptr) {
waitee_buf_ptr->next = NULL;
waitee_buf_ptr->used = 0;
}
+ DeadlockChecker checker(trx, lock, s_lock_mark_counter, waitee_buf_ptr);
+
victim_trx = checker.search();
/* Report waits to upper layer, as needed. */
@@ -8166,15 +8164,18 @@ DeadlockChecker::check_and_resolve(const lock_t* lock, const trx_t* trx)
if (checker.is_too_deep()) {
ut_ad(trx == checker.m_start);
+ ut_ad(trx == victim_trx);
- victim_trx = trx_arbitrate(
- trx, checker.m_wait_lock->trx);
-
- if (victim_trx == NULL) {
- victim_trx = trx;
+#ifdef WITH_WSREP
+ if (!wsrep_thd_is_BF(victim_trx->mysql_thd, TRUE))
+ {
+#endif /* WITH_WSREP */
+ rollback_print(victim_trx, lock);
+#ifdef WITH_WSREP
+ } else {
+ /* BF processor */;
}
-
- rollback_print(victim_trx, lock);
+#endif /* WITH_WSREP */
MONITOR_INC(MONITOR_DEADLOCK);
@@ -8231,7 +8232,6 @@ lock_trx_alloc_locks(trx_t* trx)
}
}
-
/*************************************************************//**
Updates the lock table when a page is split and merged to
two pages. */
diff --git a/storage/innobase/lock/lock0prdt.cc b/storage/innobase/lock/lock0prdt.cc
index 15208a004be..d26ae0f91e4 100644
--- a/storage/innobase/lock/lock0prdt.cc
+++ b/storage/innobase/lock/lock0prdt.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -452,7 +452,7 @@ lock_prdt_add_to_queue(
RecLock rec_lock(index, block, PRDT_HEAPNO, type_mode);
- return(rec_lock.create(trx, caller_owns_trx_mutex, prdt));
+ return(rec_lock.create(trx, caller_owns_trx_mutex, true, prdt));
}
/*********************************************************************//**
@@ -838,7 +838,7 @@ lock_prdt_lock(
RecLock rec_lock(index, block, PRDT_HEAPNO, prdt_mode);
- lock = rec_lock.create(trx, false);
+ lock = rec_lock.create(trx, false, true);
status = LOCK_REC_SUCCESS_CREATED;
@@ -954,7 +954,7 @@ lock_place_prdt_page_lock(
RecID rec_id(space, page_no, PRDT_HEAPNO);
RecLock rec_lock(index, rec_id, mode);
- rec_lock.create(trx, false);
+ rec_lock.create(trx, false, true);
#ifdef PRDT_DIAG
printf("GIS_DIAGNOSTIC: page lock %d\n", (int) page_no);
@@ -966,14 +966,16 @@ lock_place_prdt_page_lock(
return(DB_SUCCESS);
}
-/*********************************************************************//**
-Check whether there are R-tree Page lock on a page
+/** Check whether there are R-tree Page lock on a page
+@param[in] trx trx to test the lock
+@param[in] space space id for the page
+@param[in] page_no page number
@return true if there is none */
bool
lock_test_prdt_page_lock(
-/*=====================*/
- ulint space, /*!< in: space id for the page */
- ulint page_no) /*!< in: page number */
+ const trx_t* trx,
+ ulint space,
+ ulint page_no)
{
lock_t* lock;
@@ -984,7 +986,7 @@ lock_test_prdt_page_lock(
lock_mutex_exit();
- return(lock == NULL);
+ return(lock == NULL || trx == lock->trx);
}
/*************************************************************//**
@@ -1024,14 +1026,13 @@ lock_prdt_rec_move(
lock_mutex_exit();
}
-/*************************************************************//**
-Removes predicate lock objects set on an index page which is discarded. */
+/** Removes predicate lock objects set on an index page which is discarded.
+@param[in] block page to be discarded
+@param[in] lock_hash lock hash */
void
-lock_prdt_free_from_discard_page(
-/*=============================*/
- const buf_block_t* block, /*!< in: page to be discarded */
+lock_prdt_page_free_from_discard(
+ const buf_block_t* block,
hash_table_t* lock_hash)
- /*!< in: lock hash */
{
lock_t* lock;
lock_t* next_lock;
diff --git a/storage/innobase/lock/lock0wait.cc b/storage/innobase/lock/lock0wait.cc
index 83e8d69b384..7536fd88c42 100644
--- a/storage/innobase/lock/lock0wait.cc
+++ b/storage/innobase/lock/lock0wait.cc
@@ -192,10 +192,10 @@ wsrep_is_BF_lock_timeout(
if (wsrep_on(trx->mysql_thd) &&
wsrep_thd_is_BF(trx->mysql_thd, FALSE)) {
fprintf(stderr, "WSREP: BF lock wait long\n");
- srv_print_innodb_monitor = TRUE;
- srv_print_innodb_lock_monitor = TRUE;
- os_event_set(srv_monitor_event);
- return TRUE;
+ srv_print_innodb_monitor = TRUE;
+ srv_print_innodb_lock_monitor = TRUE;
+ os_event_set(srv_monitor_event);
+ return TRUE;
}
return FALSE;
}
@@ -398,8 +398,8 @@ lock_wait_suspend_thread(
if (lock_wait_timeout < 100000000
&& wait_time > (double) lock_wait_timeout
#ifdef WITH_WSREP
- && (!wsrep_on(trx->mysql_thd) ||
- (!wsrep_is_BF_lock_timeout(trx) && trx->error_state != DB_DEADLOCK))
+ && (!wsrep_on(trx->mysql_thd) ||
+ (!wsrep_is_BF_lock_timeout(trx) && trx->error_state != DB_DEADLOCK))
#endif /* WITH_WSREP */
&& !trx_is_high_priority(trx)) {
@@ -570,7 +570,7 @@ DECLARE_THREAD(lock_wait_timeout_thread)(
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
diff --git a/storage/innobase/log/log0crypt.cc b/storage/innobase/log/log0crypt.cc
index 1906189c3b4..3a4447d2b85 100644
--- a/storage/innobase/log/log0crypt.cc
+++ b/storage/innobase/log/log0crypt.cc
@@ -97,8 +97,6 @@ get_crypt_info(
/*===========*/
ib_uint64_t checkpoint_no)
{
- /* so that no one is modifying array while we search */
- ut_ad(mutex_own(&(log_sys->mutex)));
size_t items = crypt_info.size();
/* a log block only stores 4-bytes of checkpoint no */
diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc
index bdbcaa02dfa..95090c0890a 100644
--- a/storage/innobase/log/log0log.cc
+++ b/storage/innobase/log/log0log.cc
@@ -32,6 +32,7 @@ Created 12/9/1995 Heikki Tuuri
*******************************************************/
#include "ha_prototypes.h"
+#include <debug_sync.h>
#include "log0log.h"
@@ -39,14 +40,15 @@ Created 12/9/1995 Heikki Tuuri
#include "log0log.ic"
#endif
-#ifndef UNIV_HOTBACKUP
#include "mem0mem.h"
#include "buf0buf.h"
+#ifndef UNIV_HOTBACKUP
#include "buf0flu.h"
#include "srv0srv.h"
#include "log0recv.h"
#include "fil0fil.h"
#include "dict0boot.h"
+#include "dict0stats_bg.h"
#include "srv0srv.h"
#include "srv0start.h"
#include "trx0sys.h"
@@ -54,6 +56,7 @@ Created 12/9/1995 Heikki Tuuri
#include "trx0roll.h"
#include "srv0mon.h"
#include "sync0sync.h"
+#endif /* !UNIV_HOTBACKUP */
/* Used for debugging */
// #define DEBUG_CRYPT 1
@@ -89,14 +92,14 @@ log_t* log_sys = NULL;
/** Whether to generate and require checksums on the redo log pages */
my_bool innodb_log_checksums;
-/* Next log block number to do dummy record filling if no log records written
-for a while */
-static ulint next_lbn_to_pad = 0;
-
/** Pointer to the log checksum calculation function */
log_checksum_func_t log_checksum_algorithm_ptr;
+/* Next log block number to do dummy record filling if no log records written
+for a while */
+static ulint next_lbn_to_pad = 0;
+
/* These control how often we print warnings if the last checkpoint is too
old */
bool log_has_printed_chkp_warning = false;
@@ -141,6 +144,7 @@ void
log_io_complete_checkpoint(void);
/*============================*/
+#ifndef UNIV_HOTBACKUP
/****************************************************************//**
Returns the oldest modified block lsn in the pool, or log_sys->lsn if none
exists.
@@ -163,6 +167,7 @@ log_buf_pool_get_oldest_modification(void)
return(lsn);
}
+#endif /* !UNIV_HOTBACKUP */
/** Extends the log buffer.
@param[in] len requested minimum size in bytes */
@@ -174,20 +179,20 @@ log_buffer_extend(
ulint move_end;
byte tmp_buf[OS_FILE_LOG_BLOCK_SIZE];
- log_mutex_enter();
+ log_mutex_enter_all();
while (log_sys->is_extending) {
/* Another thread is trying to extend already.
Needs to wait for. */
- log_mutex_exit();
+ log_mutex_exit_all();
log_buffer_flush_to_disk();
- log_mutex_enter();
+ log_mutex_enter_all();
if (srv_log_buffer_size > len / UNIV_PAGE_SIZE) {
/* Already extended enough by the others */
- log_mutex_exit();
+ log_mutex_exit_all();
return;
}
}
@@ -209,11 +214,11 @@ log_buffer_extend(
!= ut_calc_align_down(log_sys->buf_next_to_write,
OS_FILE_LOG_BLOCK_SIZE)) {
/* Buffer might have >1 blocks to write still. */
- log_mutex_exit();
+ log_mutex_exit_all();
log_buffer_flush_to_disk();
- log_mutex_enter();
+ log_mutex_enter_all();
}
move_start = ut_calc_align_down(
@@ -231,11 +236,16 @@ log_buffer_extend(
/* reallocate log buffer */
srv_log_buffer_size = len / UNIV_PAGE_SIZE + 1;
ut_free(log_sys->buf_ptr);
+
+ log_sys->buf_size = LOG_BUFFER_SIZE;
+
log_sys->buf_ptr = static_cast<byte*>(
- ut_zalloc_nokey(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE));
+ ut_zalloc_nokey(log_sys->buf_size * 2 + OS_FILE_LOG_BLOCK_SIZE));
log_sys->buf = static_cast<byte*>(
ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE));
- log_sys->buf_size = LOG_BUFFER_SIZE;
+
+ log_sys->first_in_use = true;
+
log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
- LOG_BUF_FLUSH_MARGIN;
@@ -245,12 +255,41 @@ log_buffer_extend(
ut_ad(log_sys->is_extending);
log_sys->is_extending = false;
- log_mutex_exit();
+ log_mutex_exit_all();
ib::info() << "innodb_log_buffer_size was extended to "
<< LOG_BUFFER_SIZE << ".";
}
+#ifndef UNIV_HOTBACKUP
+/** Calculate actual length in redo buffer and file including
+block header and trailer.
+@param[in] len length to write
+@return actual length to write including header and trailer. */
+static inline
+ulint
+log_calculate_actual_len(
+ ulint len)
+{
+ ut_ad(log_mutex_own());
+
+ /* actual length stored per block */
+ const ulint len_per_blk = OS_FILE_LOG_BLOCK_SIZE
+ - (LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE);
+
+ /* actual data length in last block already written */
+ ulint extra_len = (log_sys->buf_free % OS_FILE_LOG_BLOCK_SIZE);
+
+ ut_ad(extra_len >= LOG_BLOCK_HDR_SIZE);
+ extra_len -= LOG_BLOCK_HDR_SIZE;
+
+ /* total extra length for block header and trailer */
+ extra_len = ((len + extra_len) / len_per_blk)
+ * (LOG_BLOCK_HDR_SIZE + LOG_BLOCK_TRL_SIZE);
+
+ return(len + extra_len);
+}
+
/** Check margin not to overwrite transaction log from the last checkpoint.
If would estimate the log write to exceed the log_group_capacity,
waits for the checkpoint is done enough.
@@ -260,7 +299,7 @@ void
log_margin_checkpoint_age(
ulint len)
{
- ulint margin = len * 2;
+ ulint margin = log_calculate_actual_len(len);
ut_ad(log_mutex_own());
@@ -282,8 +321,11 @@ log_margin_checkpoint_age(
return;
}
- while (log_sys->lsn - log_sys->last_checkpoint_lsn + margin
- > log_sys->log_group_capacity) {
+ /* Our margin check should ensure that we never reach this condition.
+ Try to do checkpoint once. We cannot keep waiting here as it might
+ result in hang in case the current mtr has latch on oldest lsn */
+ if (log_sys->lsn - log_sys->last_checkpoint_lsn + margin
+ > log_sys->log_group_capacity) {
/* The log write of 'len' might overwrite the transaction log
after the last checkpoint. Makes checkpoint. */
@@ -298,6 +340,8 @@ log_margin_checkpoint_age(
log_sys->check_flush_or_checkpoint = true;
log_mutex_exit();
+ DEBUG_SYNC_C("margin_checkpoint_age_rescue");
+
if (!flushed_enough) {
os_thread_sleep(100000);
}
@@ -308,7 +352,7 @@ log_margin_checkpoint_age(
return;
}
-
+#endif /* !UNIV_HOTBACKUP */
/** Open the log for log_write_low. The log must be closed with log_close.
@param[in] len length of the data to be written
@return start lsn of the log record */
@@ -317,10 +361,6 @@ log_reserve_and_open(
ulint len)
{
ulint len_upper_limit;
-#ifdef UNIV_LOG_ARCHIVE
- lsn_t archived_lsn_age;
- ulint dummy;
-#endif /* UNIV_LOG_ARCHIVE */
#ifdef UNIV_DEBUG
ulint count = 0;
#endif /* UNIV_DEBUG */
@@ -352,8 +392,9 @@ loop:
if (log_sys->buf_free + len_upper_limit > log_sys->buf_size) {
log_mutex_exit();
- /* Not enough free space, do a write of the log buffer */
+ DEBUG_SYNC_C("log_buf_size_exceeded");
+ /* Not enough free space, do a write of the log buffer */
log_buffer_sync_in_background(false);
srv_stats.log_waits.inc();
@@ -480,6 +521,9 @@ log_close(void)
checkpoint_age = lsn - log->last_checkpoint_lsn;
if (checkpoint_age >= log->log_group_capacity) {
+ DBUG_EXECUTE_IF(
+ "print_all_chkp_warnings",
+ log_has_printed_chkp_warning = false;);
if (!log_has_printed_chkp_warning
|| difftime(time(NULL), log_last_warning_time) > 15) {
@@ -521,7 +565,9 @@ log_group_get_capacity(
/*===================*/
const log_group_t* group) /*!< in: log group */
{
- ut_ad(log_mutex_own());
+ /* The lsn parameters are updated while holding both the mutexes
+ and it is ok to have either of them while reading */
+ ut_ad(log_mutex_own() || log_write_mutex_own());
return((group->file_size - LOG_FILE_HDR_SIZE) * group->n_files);
}
@@ -538,7 +584,9 @@ log_group_calc_size_offset(
log group */
const log_group_t* group) /*!< in: log group */
{
- ut_ad(log_mutex_own());
+ /* The lsn parameters are updated while holding both the mutexes
+ and it is ok to have either of them while reading */
+ ut_ad(log_mutex_own() || log_write_mutex_own());
return(offset - LOG_FILE_HDR_SIZE * (1 + offset / group->file_size));
}
@@ -555,7 +603,9 @@ log_group_calc_real_offset(
log group */
const log_group_t* group) /*!< in: log group */
{
- ut_ad(log_mutex_own());
+ /* The lsn parameters are updated while holding both the mutexes
+ and it is ok to have either of them while reading */
+ ut_ad(log_mutex_own() || log_write_mutex_own());
return(offset + LOG_FILE_HDR_SIZE
* (1 + offset / (group->file_size - LOG_FILE_HDR_SIZE)));
@@ -576,11 +626,14 @@ log_group_calc_lsn_offset(
lsn_t group_size;
lsn_t offset;
- ut_ad(log_mutex_own());
+ /* The lsn parameters are updated while holding both the mutexes
+ and it is ok to have either of them while reading */
+ ut_ad(log_mutex_own() || log_write_mutex_own());
gr_lsn = group->lsn;
- gr_lsn_size_offset = log_group_calc_size_offset(group->lsn_offset, group);
+ gr_lsn_size_offset = log_group_calc_size_offset(
+ group->lsn_offset, group);
group_size = log_group_get_capacity(group);
@@ -605,8 +658,6 @@ log_group_calc_lsn_offset(
return(log_group_calc_real_offset(offset, group));
}
-#endif /* !UNIV_HOTBACKUP */
-
/*******************************************************************//**
Calculates where in log files we find a specified lsn.
@return log file number */
@@ -646,7 +697,7 @@ log_calc_where_lsn_is(
return(file_no);
}
-#ifndef UNIV_HOTBACKUP
+
/********************************************************//**
Sets the field values in group to correspond to a given lsn. For this function
to work, the values must already be correctly initialized to correspond to
@@ -661,14 +712,14 @@ log_group_set_fields(
group->lsn_offset = log_group_calc_lsn_offset(lsn, group);
group->lsn = lsn;
}
-
+#ifndef UNIV_HOTBACKUP
/*****************************************************************//**
Calculates the recommended highest values for lsn - last_checkpoint_lsn
and lsn - buf_get_oldest_modification().
@retval true on success
@retval false if the smallest log group is too small to
accommodate the number of OS threads in the database server */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
log_calc_max_ages(void)
/*===================*/
@@ -754,6 +805,7 @@ log_init(void)
log_sys = static_cast<log_t*>(ut_zalloc_nokey(sizeof(log_t)));
mutex_create(LATCH_ID_LOG_SYS, &log_sys->mutex);
+ mutex_create(LATCH_ID_LOG_WRITE, &log_sys->write_mutex);
mutex_create(LATCH_ID_LOG_FLUSH_ORDER, &log_sys->log_flush_order_mutex);
@@ -765,13 +817,14 @@ log_init(void)
ut_a(LOG_BUFFER_SIZE >= 16 * OS_FILE_LOG_BLOCK_SIZE);
ut_a(LOG_BUFFER_SIZE >= 4 * UNIV_PAGE_SIZE);
- log_sys->buf_ptr = static_cast<byte*>(
- ut_zalloc_nokey(LOG_BUFFER_SIZE + OS_FILE_LOG_BLOCK_SIZE));
+ log_sys->buf_size = LOG_BUFFER_SIZE;
+ log_sys->buf_ptr = static_cast<byte*>(
+ ut_zalloc_nokey(log_sys->buf_size * 2 + OS_FILE_LOG_BLOCK_SIZE));
log_sys->buf = static_cast<byte*>(
ut_align(log_sys->buf_ptr, OS_FILE_LOG_BLOCK_SIZE));
- log_sys->buf_size = LOG_BUFFER_SIZE;
+ log_sys->first_in_use = true;
log_sys->max_buf_free = log_sys->buf_size / LOG_BUF_FLUSH_RATIO
- LOG_BUF_FLUSH_MARGIN;
@@ -817,7 +870,7 @@ log_init(void)
/******************************************************************//**
Inits a log group to the log system.
@return true if success, false if not */
-__attribute__((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
bool
log_group_init(
/*===========*/
@@ -865,43 +918,9 @@ log_group_init(
ut_align(group->checkpoint_buf_ptr,OS_FILE_LOG_BLOCK_SIZE));
UT_LIST_ADD_LAST(log_sys->log_groups, group);
-
return(log_calc_max_ages());
}
-
-/******************************************************//**
-Update log_sys after write completion. */
-static
-void
-log_sys_write_completion(void)
-/*==========================*/
-{
- ulint move_start;
- ulint move_end;
-
- ut_ad(log_mutex_own());
-
- log_sys->write_lsn = log_sys->lsn;
- log_sys->buf_next_to_write = log_sys->write_end_offset;
-
- if (log_sys->write_end_offset > log_sys->max_buf_free / 2) {
- /* Move the log buffer content to the start of the
- buffer */
-
- move_start = ut_calc_align_down(
- log_sys->write_end_offset,
- OS_FILE_LOG_BLOCK_SIZE);
- move_end = ut_calc_align(log_sys->buf_free,
- OS_FILE_LOG_BLOCK_SIZE);
-
- ut_memmove(log_sys->buf, log_sys->buf + move_start,
- move_end - move_start);
- log_sys->buf_free -= move_start;
-
- log_sys->buf_next_to_write -= move_start;
- }
-}
-
+#endif /* !UNIV_HOTBACKUP */
/******************************************************//**
Completes an i/o to a log file. */
void
@@ -954,7 +973,7 @@ log_group_file_header_flush(
byte* buf;
lsn_t dest_offset;
- ut_ad(log_mutex_own());
+ ut_ad(log_write_mutex_own());
ut_ad(!recv_no_log_write);
ut_ad(group->id == 0);
ut_a(nth_file < group->n_files);
@@ -1034,7 +1053,7 @@ log_group_write_buf(
lsn_t next_offset;
ulint i;
- ut_ad(log_mutex_own());
+ ut_ad(log_write_mutex_own());
ut_ad(!recv_no_log_write);
ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(start_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
@@ -1157,6 +1176,41 @@ log_write_flush_to_disk_low()
os_event_set(log_sys->flush_event);
}
+/** Switch the log buffer in use, and copy the content of last block
+from old log buffer to the head of the to be used one. Thus, buf_free and
+buf_next_to_write would be changed accordingly */
+static inline
+void
+log_buffer_switch()
+{
+ ut_ad(log_mutex_own());
+ ut_ad(log_write_mutex_own());
+
+ const byte* old_buf = log_sys->buf;
+ ulint area_end = ut_calc_align(log_sys->buf_free,
+ OS_FILE_LOG_BLOCK_SIZE);
+
+ if (log_sys->first_in_use) {
+ ut_ad(log_sys->buf == ut_align(log_sys->buf_ptr,
+ OS_FILE_LOG_BLOCK_SIZE));
+ log_sys->buf += log_sys->buf_size;
+ } else {
+ log_sys->buf -= log_sys->buf_size;
+ ut_ad(log_sys->buf == ut_align(log_sys->buf_ptr,
+ OS_FILE_LOG_BLOCK_SIZE));
+ }
+
+ log_sys->first_in_use = !log_sys->first_in_use;
+
+ /* Copy the last block to new buf */
+ ut_memcpy(log_sys->buf,
+ old_buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
+ OS_FILE_LOG_BLOCK_SIZE);
+
+ log_sys->buf_free %= OS_FILE_LOG_BLOCK_SIZE;
+ log_sys->buf_next_to_write = log_sys->buf_free;
+}
+
/** Ensure that the log has been written to the log file up to a given
log entry (such as that of a transaction commit). Start a new write, or
wait and check if an already running write is covering the request.
@@ -1172,8 +1226,8 @@ log_write_up_to(
#ifdef UNIV_DEBUG
ulint loop_count = 0;
#endif /* UNIV_DEBUG */
- ib_uint64_t write_lsn;
- ib_uint64_t flush_lsn;
+ byte* write_buf;
+ lsn_t write_lsn;
ut_ad(!srv_read_only_mode);
@@ -1199,7 +1253,7 @@ loop:
}
#endif
- log_mutex_enter();
+ log_write_mutex_enter();
ut_ad(!recv_no_log_write);
lsn_t limit_lsn = flush_to_disk
@@ -1207,18 +1261,24 @@ loop:
: log_sys->write_lsn;
if (limit_lsn >= lsn) {
- log_mutex_exit();
+ log_write_mutex_exit();
return;
}
#ifdef _WIN32
+# ifndef UNIV_HOTBACKUP
/* write requests during fil_flush() might not be good for Windows */
if (log_sys->n_pending_flushes > 0
|| !os_event_is_set(log_sys->flush_event)) {
- log_mutex_exit();
+ log_write_mutex_exit();
os_event_wait(log_sys->flush_event);
goto loop;
}
+# else
+ if (log_sys->n_pending_flushes > 0) {
+ goto loop;
+ }
+# endif /* !UNIV_HOTBACKUP */
#endif /* _WIN32 */
/* If it is a write call we should just go ahead and do it
@@ -1233,7 +1293,7 @@ loop:
for us. */
bool work_done = log_sys->current_flush_lsn >= lsn;
- log_mutex_exit();
+ log_write_mutex_exit();
os_event_wait(log_sys->flush_event);
@@ -1244,10 +1304,11 @@ loop:
}
}
+ log_mutex_enter();
if (!flush_to_disk
&& log_sys->buf_free == log_sys->buf_next_to_write) {
/* Nothing to write and no flush to disk requested */
- log_mutex_exit();
+ log_mutex_exit_all();
return;
}
@@ -1262,7 +1323,6 @@ loop:
DBUG_PRINT("ib_log", ("write " LSN_PF " to " LSN_PF,
log_sys->write_lsn,
log_sys->lsn));
-
if (flush_to_disk) {
log_sys->n_pending_flushes++;
log_sys->current_flush_lsn = log_sys->lsn;
@@ -1271,14 +1331,12 @@ loop:
if (log_sys->buf_free == log_sys->buf_next_to_write) {
/* Nothing to write, flush only */
- log_mutex_exit();
+ log_mutex_exit_all();
log_write_flush_to_disk_low();
return;
}
}
- group = UT_LIST_GET_FIRST(log_sys->log_groups);
-
start_offset = log_sys->buf_next_to_write;
end_offset = log_sys->buf_free;
@@ -1292,16 +1350,23 @@ loop:
log_sys->buf + area_end - OS_FILE_LOG_BLOCK_SIZE,
log_sys->next_checkpoint_no);
+ write_lsn = log_sys->lsn;
+ write_buf = log_sys->buf;
+
+ log_buffer_switch();
+
group = UT_LIST_GET_FIRST(log_sys->log_groups);
+ log_group_set_fields(group, log_sys->write_lsn);
+
+ log_mutex_exit();
/* Calculate pad_size if needed. */
pad_size = 0;
if (write_ahead_size > OS_FILE_LOG_BLOCK_SIZE) {
lsn_t end_offset;
ulint end_offset_in_unit;
-
end_offset = log_group_calc_lsn_offset(
- ut_uint64_align_up(log_sys->lsn,
+ ut_uint64_align_up(write_lsn,
OS_FILE_LOG_BLOCK_SIZE),
group);
end_offset_in_unit = (ulint) (end_offset % write_ahead_size);
@@ -1317,13 +1382,12 @@ loop:
pad_size = log_sys->buf_size - area_end;
}
- ::memset(log_sys->buf + area_end, 0, pad_size);
+ ::memset(write_buf + area_end, 0, pad_size);
}
}
-
/* Do the write to the log files */
log_group_write_buf(
- group, log_sys->buf + area_start,
+ group, write_buf + area_start,
area_end - area_start + pad_size,
#ifdef UNIV_DEBUG
pad_size,
@@ -1331,14 +1395,8 @@ loop:
ut_uint64_align_down(log_sys->write_lsn,
OS_FILE_LOG_BLOCK_SIZE),
start_offset - area_start);
-
srv_stats.log_padded.add(pad_size);
-
- log_sys->write_end_offset = log_sys->buf_free;
-
- log_group_set_fields(group, log_sys->write_lsn);
-
- log_sys_write_completion();
+ log_sys->write_lsn = write_lsn;
#ifndef _WIN32
if (srv_unix_file_flush_method == SRV_UNIX_O_DSYNC) {
@@ -1348,15 +1406,14 @@ loop:
}
#endif /* !_WIN32 */
- log_mutex_exit();
+ log_write_mutex_exit();
if (flush_to_disk) {
log_write_flush_to_disk_low();
- write_lsn = log_sys->write_lsn;
- flush_lsn = log_sys->flushed_to_disk_lsn;
-
- innobase_mysql_log_notify(write_lsn, flush_lsn);
+ ib_uint64_t write_lsn = log_sys->write_lsn;
+ ib_uint64_t flush_lsn = log_sys->flushed_to_disk_lsn;
+ innobase_mysql_log_notify(write_lsn, flush_lsn);
}
}
@@ -1425,7 +1482,7 @@ log_flush_margin(void)
log_write_up_to(lsn, false);
}
}
-
+#ifndef UNIV_HOTBACKUP
/** Advances the smallest lsn for which there are unflushed dirty blocks in the
buffer pool.
NOTE: this function may only be called if the calling thread owns no
@@ -1494,7 +1551,7 @@ log_preflush_pool_modified_pages(
return(success);
}
-
+#endif /* !UNIV_HOTBACKUP */
/******************************************************//**
Completes a checkpoint. */
static
@@ -1608,7 +1665,6 @@ log_group_checkpoint(
ut_ad(((ulint) group & 0x1UL) == 0);
}
-#endif /* !UNIV_HOTBACKUP */
#ifdef UNIV_HOTBACKUP
/******************************************************//**
@@ -1633,10 +1689,10 @@ log_reset_first_header_and_checkpoint(
lsn = start + LOG_BLOCK_HDR_SIZE;
/* Write the label of mysqlbackup --restore */
- strcpy((char*) hdr_buf + LOG_HEADER_CREATOR, "ibbackup ");
+ strcpy((char*)hdr_buf + LOG_HEADER_CREATOR, LOG_HEADER_CREATOR_CURRENT);
ut_sprintf_timestamp((char*) hdr_buf
+ (LOG_HEADER_CREATOR
- + (sizeof "ibbackup ") - 1));
+ + (sizeof LOG_HEADER_CREATOR_CURRENT) - 1));
buf = hdr_buf + LOG_CHECKPOINT_1;
memset(buf, 0, OS_FILE_LOG_BLOCK_SIZE);
@@ -1644,8 +1700,8 @@ log_reset_first_header_and_checkpoint(
mach_write_to_8(buf + LOG_CHECKPOINT_LSN, lsn);
log_crypt_write_checkpoint_buf(buf);
- mach_write_to_8(buf + LOG_CHECKPOINT_OFFSET,
+ mach_write_to_8(buf + LOG_CHECKPOINT_OFFSET,
LOG_FILE_HDR_SIZE + LOG_BLOCK_HDR_SIZE);
mach_write_to_8(buf + LOG_CHECKPOINT_LOG_BUF_SIZE, 2 * 1024 * 1024);
@@ -1693,6 +1749,16 @@ log_write_checkpoint_info(
}
}
+ /* generate key version and key used to encrypt future blocks,
+ *
+ * NOTE: the +1 is as the next_checkpoint_no will be updated once
+ * the checkpoint info has been written and THEN blocks will be encrypted
+ * with new key
+ */
+ if (srv_encrypt_log) {
+ log_crypt_set_ver_and_key(log_sys->next_checkpoint_no + 1);
+ }
+
log_mutex_exit();
MONITOR_INC(MONITOR_NUM_CHECKPOINT);
@@ -1701,6 +1767,12 @@ log_write_checkpoint_info(
/* Wait for the checkpoint write to complete */
rw_lock_s_lock(&log_sys->checkpoint_lock);
rw_lock_s_unlock(&log_sys->checkpoint_lock);
+
+ DEBUG_SYNC_C("checkpoint_completed");
+
+ DBUG_EXECUTE_IF(
+ "crash_after_checkpoint",
+ DBUG_SUICIDE(););
}
}
@@ -1777,22 +1849,21 @@ log_checkpoint(
write-ahead-logging algorithm ensures that the log has been
flushed up to oldest_lsn. */
+ ut_ad(oldest_lsn >= log_sys->last_checkpoint_lsn);
if (!write_always
&& oldest_lsn
- == log_sys->last_checkpoint_lsn + SIZE_OF_MLOG_CHECKPOINT) {
+ <= log_sys->last_checkpoint_lsn + SIZE_OF_MLOG_CHECKPOINT) {
/* Do nothing, because nothing was logged (other than
a MLOG_CHECKPOINT marker) since the previous checkpoint. */
log_mutex_exit();
return(true);
}
-
/* Repeat the MLOG_FILE_NAME records after the checkpoint, in
case some log records between the checkpoint and log_sys->lsn
need them. Finally, write a MLOG_CHECKPOINT marker. Redo log
apply expects to see a MLOG_CHECKPOINT after the checkpoint,
except on clean shutdown, where the log will be empty after
the checkpoint.
-
It is important that we write out the redo log before any
further dirty pages are flushed to the tablespace files. At
this point, because log_mutex_own(), mtr_commit() in other
@@ -1812,12 +1883,26 @@ log_checkpoint(
log_write_up_to(flush_lsn, true);
+ DBUG_EXECUTE_IF(
+ "using_wa_checkpoint_middle",
+ if (write_always) {
+ DEBUG_SYNC_C("wa_checkpoint_middle");
+
+ const my_bool b = TRUE;
+ buf_flush_page_cleaner_disabled_debug_update(
+ NULL, NULL, NULL, &b);
+ dict_stats_disabled_debug_update(
+ NULL, NULL, NULL, &b);
+ srv_master_thread_disabled_debug_update(
+ NULL, NULL, NULL, &b);
+ });
+
log_mutex_enter();
- ut_ad(log_sys->flushed_to_disk_lsn >= oldest_lsn);
+ ut_ad(log_sys->flushed_to_disk_lsn >= flush_lsn);
+ ut_ad(flush_lsn >= oldest_lsn);
- if (!write_always
- && log_sys->last_checkpoint_lsn >= oldest_lsn) {
+ if (log_sys->last_checkpoint_lsn >= oldest_lsn) {
log_mutex_exit();
return(true);
}
@@ -1838,14 +1923,8 @@ log_checkpoint(
log_sys->next_checkpoint_lsn = oldest_lsn;
log_write_checkpoint_info(sync);
ut_ad(!log_mutex_own());
+
return(true);
- /* generate key version and key used to encrypt future blocks,
- *
- * NOTE: the +1 is as the next_checkpoint_no will be updated once
- * the checkpoint info has been written and THEN blocks will be encrypted
- * with new key
- */
- log_crypt_set_ver_and_key(log_sys->next_checkpoint_no + 1);
}
/** Make a checkpoint at or after a specified LSN.
@@ -2001,6 +2080,7 @@ loop:
univ_page_size,
(ulint) (source_offset % univ_page_size.physical()),
len, buf, NULL, NULL);
+
#ifdef DEBUG_CRYPT
fprintf(stderr, "BEFORE DECRYPT: block: %lu checkpoint: %lu %.8lx %.8lx offset %lu\n",
log_block_get_hdr_no(buf),
@@ -2018,7 +2098,6 @@ loop:
log_block_calc_checksum(buf),
log_block_get_checksum(buf));
#endif
-
start_lsn += len;
buf += len;
@@ -2063,6 +2142,7 @@ logs_empty_and_mark_files_at_shutdown(void)
ulint pending_io;
enum srv_thread_type active_thd;
const char* thread_name;
+ dberr_t err = DB_SUCCESS;
ib::info() << "Starting shutdown...";
@@ -2312,7 +2392,12 @@ loop:
srv_shutdown_lsn = lsn;
if (!srv_read_only_mode) {
- fil_write_flushed_lsn(lsn);
+ err = fil_write_flushed_lsn(lsn);
+
+ if (err != DB_SUCCESS) {
+ ib::error() << "Writing flushed lsn " << lsn
+ << " failed at shutdown error " << err;
+ }
}
fil_close_all_files();
@@ -2465,6 +2550,7 @@ log_shutdown(void)
rw_lock_free(&log_sys->checkpoint_lock);
mutex_free(&log_sys->mutex);
+ mutex_free(&log_sys->write_mutex);
mutex_free(&log_sys->log_flush_order_mutex);
recv_sys_close();
@@ -2535,10 +2621,12 @@ log_scrub()
/*=========*/
{
ulint cur_lbn = log_block_convert_lsn_to_no(log_sys->lsn);
+
if (next_lbn_to_pad == cur_lbn)
{
log_pad_current_log_block();
}
+
next_lbn_to_pad = log_block_convert_lsn_to_no(log_sys->lsn);
}
@@ -2577,7 +2665,7 @@ DECLARE_THREAD(log_scrub_thread)(
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 1f684a89b0a..a9c37fbdc3d 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -28,10 +28,9 @@ Created 9/20/1997 Heikki Tuuri
#include "ha_prototypes.h"
#include <vector>
-#include <my_systemd.h>
-
#include <map>
#include <string>
+#include <my_systemd.h>
#include "log0recv.h"
@@ -39,6 +38,10 @@ Created 9/20/1997 Heikki Tuuri
#include "log0recv.ic"
#endif
+#ifdef HAVE_MY_AES_H
+#include <my_aes.h>
+#endif
+
#include "log0crypt.h"
#include "mem0mem.h"
@@ -54,21 +57,21 @@ Created 9/20/1997 Heikki Tuuri
#include "trx0undo.h"
#include "trx0rec.h"
#include "fil0fil.h"
-#include "fil0crypt.h"
#include "fsp0sysspace.h"
#include "ut0new.h"
+#include "row0trunc.h"
#ifndef UNIV_HOTBACKUP
# include "buf0rea.h"
# include "srv0srv.h"
# include "srv0start.h"
# include "trx0roll.h"
# include "row0merge.h"
-#include "row0trunc.h"
#else /* !UNIV_HOTBACKUP */
-/** This is set to FALSE if the backup was originally taken with the
+/** This is set to false if the backup was originally taken with the
mysqlbackup --include regexp option: then we do not want to create tables in
directories which were not included */
bool recv_replay_file_ops = true;
+#include "fut0lst.h"
#endif /* !UNIV_HOTBACKUP */
/** Log records are stored in the hash table in chunks at most of this size;
@@ -88,6 +91,10 @@ volatile bool recv_recovery_on;
#ifndef UNIV_HOTBACKUP
/** TRUE when recv_init_crash_recovery() has been called. */
bool recv_needed_recovery;
+#else
+# define recv_needed_recovery false
+# define buf_pool_get_curr_size() (5 * 1024 * 1024)
+#endif /* !UNIV_HOTBACKUP */
# ifdef UNIV_DEBUG
/** TRUE if writing to the redo log (mtr_commit) is forbidden.
Protected by log_sys->mutex. */
@@ -108,13 +115,18 @@ buffer pool before the pages have been recovered to the up-to-date state.
TRUE means that recovery is running and no operations on the log files
are allowed yet: the variable name is misleading. */
+#ifndef UNIV_HOTBACKUP
bool recv_no_ibuf_operations;
/** TRUE when the redo log is being backed up */
# define recv_is_making_a_backup false
/** TRUE when recovering from a backed up redo log file */
# define recv_is_from_backup false
#else /* !UNIV_HOTBACKUP */
-# define recv_needed_recovery false
+/** true if the backup is an offline backup */
+volatile bool is_online_redo_copy = true;
+/**true if the last flushed lsn read at the start of backup */
+volatile lsn_t backup_redo_log_flushed_lsn;
+
/** TRUE when the redo log is being backed up */
bool recv_is_making_a_backup = false;
/** TRUE when recovering from a backed up redo log file */
@@ -205,20 +217,24 @@ static recv_spaces_t recv_spaces;
@param[in,out] name file name
@param[in] len length of the file name
@param[in] space_id the tablespace ID
-@param[in] deleted whether this is a MLOG_FILE_DELETE record */
+@param[in] deleted whether this is a MLOG_FILE_DELETE record
+@retval true if able to process file successfully.
+@retval false if unable to process the file */
static
-void
+bool
fil_name_process(
char* name,
ulint len,
ulint space_id,
bool deleted)
{
+ bool processed = true;
+
/* We will also insert space=NULL into the map, so that
further checks can ensure that a MLOG_FILE_NAME record was
scanned before applying any page records for the space_id. */
- os_normalize_path_for_win(name);
+ os_normalize_path(name);
file_name_t fname(std::string(name, len - 1), deleted);
std::pair<recv_spaces_t::iterator,bool> p = recv_spaces.insert(
std::make_pair(space_id, fname));
@@ -250,6 +266,42 @@ fil_name_process(
case FIL_LOAD_OK:
ut_ad(space != NULL);
+#ifdef MYSQL_ENCRYPTION
+ /* For encrypted tablespace, set key and iv. */
+ if (FSP_FLAGS_GET_ENCRYPTION(space->flags)
+ && recv_sys->encryption_list != NULL) {
+ dberr_t err;
+ encryption_list_t::iterator it;
+
+ for (it = recv_sys->encryption_list->begin();
+ it != recv_sys->encryption_list->end();
+ it++) {
+ if (it->space_id == space->id) {
+ err = fil_set_encryption(
+ space->id,
+ Encryption::AES,
+ it->key,
+ it->iv);
+ if (err != DB_SUCCESS) {
+ ib::error()
+ << "Can't set"
+ " encryption"
+ " information"
+ " for"
+ " tablespace"
+ << space->name
+ << "!";
+ }
+ ut_free(it->key);
+ ut_free(it->iv);
+ it->key = NULL;
+ it->iv = NULL;
+ it->space_id = 0;
+ }
+ }
+ }
+#endif /* MYSQL_ENCRYPTION */
+
if (f.space == NULL || f.space == space) {
f.name = fname.name;
f.space = space;
@@ -260,6 +312,7 @@ fil_name_process(
<< f.name << "' and '" << name << "'."
" You must delete one of them.";
recv_sys->found_corrupt_fs = true;
+ processed = false;
}
break;
@@ -291,6 +344,7 @@ fil_name_process(
case FIL_LOAD_INVALID:
ut_ad(space == NULL);
if (srv_force_recovery == 0) {
+#ifndef UNIV_HOTBACKUP
ib::warn() << "We do not continue the crash"
" recovery, because the table may"
" become corrupt if we cannot apply"
@@ -312,6 +366,14 @@ fil_name_process(
" remove the .ibd file, you can set"
" --innodb_force_recovery.";
recv_sys->found_corrupt_fs = true;
+#else
+ ib::warn() << "We do not continue the apply-log"
+ " operation because the tablespace may"
+ " become corrupt if we cannot apply"
+ " the log records in the redo log"
+ " records to it.";
+#endif /* !UNIV_BACKUP */
+ processed = false;
break;
}
@@ -322,8 +384,10 @@ fil_name_process(
break;
}
}
+ return(processed);
}
+#ifndef UNIV_HOTBACKUP
/** Parse or process a MLOG_FILE_* record.
@param[in] ptr redo log record
@param[in] end end of the redo log buffer
@@ -344,17 +408,10 @@ fil_name_parse(
mlog_id_t type,
bool apply)
{
-#ifdef UNIV_HOTBACKUP
- ulint flags = 0;
-#endif /* UNIV_HOTBACKUP */
-
if (type == MLOG_FILE_CREATE2) {
if (end < ptr + 4) {
return(NULL);
}
-#ifdef UNIV_HOTBACKUP
- flags = mach_read_from_4(ptr);
-#endif /* UNIV_HOTBACKUP */
ptr += 4;
}
@@ -388,6 +445,7 @@ fil_name_parse(
recv_sys->found_corrupt_log = true;
break;
}
+
fil_name_process(
reinterpret_cast<char*>(ptr), len, space_id, false);
break;
@@ -397,26 +455,16 @@ fil_name_parse(
recv_sys->found_corrupt_log = true;
break;
}
+
fil_name_process(
reinterpret_cast<char*>(ptr), len, space_id, true);
-#ifdef UNIV_HOTBACKUP
- if (apply && recv_replay_file_ops
- && fil_space_get(space_id)) {
- dberr_t err = fil_delete_tablespace(
- space_id, BUF_REMOVE_FLUSH_NO_WRITE);
- ut_a(err == DB_SUCCESS);
- }
-#endif /* UNIV_HOTBACKUP */
+
break;
case MLOG_FILE_CREATE2:
-#ifdef UNIV_HOTBACKUP
- /* if needed, invoke fil_ibd_create() with flags */
-#endif /* UNIV_HOTBACKUP */
break;
case MLOG_FILE_RENAME2:
if (corrupt) {
ib::error() << "MLOG_FILE_RENAME2 incorrect:" << ptr;
-
recv_sys->found_corrupt_log = true;
}
@@ -440,8 +488,8 @@ fil_name_parse(
|| !memchr(new_name, OS_PATH_SEPARATOR, new_len);
if (corrupt) {
- ib::error() << "MLOG_FILE_RENAME2 new_name incorrect:" << ptr;
-
+ ib::error() << "MLOG_FILE_RENAME2 new_name incorrect:" << ptr
+ << " new_name: " << new_name;
recv_sys->found_corrupt_log = true;
break;
}
@@ -456,12 +504,6 @@ fil_name_parse(
if (!apply) {
break;
}
-#ifdef UNIV_HOTBACKUP
- if (!recv_replay_file_ops) {
- break;
- }
-#endif /* UNIV_HOTBACKUP */
-
if (!fil_op_replay_rename(
space_id, first_page_no,
reinterpret_cast<const char*>(ptr),
@@ -472,6 +514,286 @@ fil_name_parse(
return(end_ptr);
}
+#else /* !UNIV_HOTBACKUP */
+/** Parse a file name retrieved from a MLOG_FILE_* record,
+and return the absolute file path corresponds to backup dir
+as well as in the form of database/tablespace
+@param[in] file_name path emitted by the redo log
+@param[out] absolute_path absolute path of tablespace
+corresponds to backup dir
+@param[out] tablespace_name name in the form of database/table */
+static
+void
+make_abs_file_path(
+ const std::string& name,
+ std::string& absolute_path,
+ std::string& tablespace_name)
+{
+ std::string file_name = name;
+ std::string path = fil_path_to_mysql_datadir;
+ size_t pos = std::string::npos;
+
+ if (is_absolute_path(file_name.c_str())) {
+
+ pos = file_name.rfind(OS_PATH_SEPARATOR);
+ std::string temp_name = file_name.substr(0, pos);
+ pos = temp_name.rfind(OS_PATH_SEPARATOR);
+ ++pos;
+ file_name = file_name.substr(pos, file_name.length());
+ path += OS_PATH_SEPARATOR + file_name;
+ } else {
+ pos = file_name.find(OS_PATH_SEPARATOR);
+ ++pos;
+ file_name = file_name.substr(pos, file_name.length());
+ path += OS_PATH_SEPARATOR + file_name;
+ }
+
+ absolute_path = path;
+
+ /* remove the .ibd extension */
+ pos = file_name.rfind(".ibd");
+ if (pos != std::string::npos)
+ tablespace_name = file_name.substr(0, pos);
+
+ /* space->name uses '/', not OS_PATH_SEPARATOR,
+ update the seperator */
+ if (OS_PATH_SEPARATOR != '/') {
+ pos = tablespace_name.find(OS_PATH_SEPARATOR);
+ while (pos != std::string::npos) {
+ tablespace_name[pos] = '/';
+ pos = tablespace_name.find(OS_PATH_SEPARATOR);
+ }
+ }
+
+}
+
+/** Wrapper around fil_name_process()
+@param[in] name absolute path of tablespace file
+@param[in] space_id the tablespace ID
+@retval true if able to process file successfully.
+@retval false if unable to process the file */
+bool
+fil_name_process(
+ const char* name,
+ ulint space_id)
+{
+ size_t length = strlen(name);
+ ++length;
+
+ char* file_name = static_cast<char*>(ut_malloc_nokey(length));
+ strncpy(file_name, name,length);
+
+ bool processed = fil_name_process(file_name, length, space_id, false);
+
+ ut_free(file_name);
+ return(processed);
+}
+
+/** Parse or process a MLOG_FILE_* record.
+@param[in] ptr redo log record
+@param[in] end end of the redo log buffer
+@param[in] space_id the tablespace ID
+@param[in] first_page_no first page number in the file
+@param[in] type MLOG_FILE_NAME or MLOG_FILE_DELETE
+or MLOG_FILE_CREATE2 or MLOG_FILE_RENAME2
+@param[in] apply whether to apply the record
+@retval pointer to next redo log record
+@retval NULL if this log record was truncated */
+static
+byte*
+fil_name_parse(
+ byte* ptr,
+ const byte* end,
+ ulint space_id,
+ ulint first_page_no,
+ mlog_id_t type,
+ bool apply)
+{
+
+ ulint flags = mach_read_from_4(ptr);
+
+ if (type == MLOG_FILE_CREATE2) {
+ if (end < ptr + 4) {
+ return(NULL);
+ }
+ ptr += 4;
+ }
+
+ if (end < ptr + 2) {
+ return(NULL);
+ }
+
+ ulint len = mach_read_from_2(ptr);
+ ptr += 2;
+ if (end < ptr + len) {
+ return(NULL);
+ }
+
+ os_normalize_path(reinterpret_cast<char*>(ptr));
+
+ /* MLOG_FILE_* records should only be written for
+ user-created tablespaces. The name must be long enough
+ and end in .ibd. */
+ bool corrupt = is_predefined_tablespace(space_id)
+ || first_page_no != 0 // TODO: multi-file user tablespaces
+ || len < sizeof "/a.ibd\0"
+ || memcmp(ptr + len - 5, DOT_IBD, 5) != 0
+ || memchr(ptr, OS_PATH_SEPARATOR, len) == NULL;
+
+ byte* end_ptr = ptr + len;
+
+ if (corrupt) {
+ recv_sys->found_corrupt_log = true;
+ return(end_ptr);
+ }
+
+ std::string abs_file_path, tablespace_name;
+ char* name = reinterpret_cast<char*>(ptr);
+ char* new_name = NULL;
+ recv_spaces_t::iterator itr;
+
+ make_abs_file_path(name, abs_file_path, tablespace_name);
+
+ if (!recv_is_making_a_backup) {
+
+ name = static_cast<char*>(ut_malloc_nokey(
+ (abs_file_path.length() + 1)));
+ strcpy(name, abs_file_path.c_str());
+ len = strlen(name) + 1;
+ }
+ switch (type) {
+ default:
+ ut_ad(0); // the caller checked this
+ case MLOG_FILE_NAME:
+ /* Don't validate tablespaces while copying redo logs
+ because backup process might keep some tablespace handles
+ open in server datadir.
+ Maintain "map of dirty tablespaces" so that assumptions
+ for other redo log records are not broken even for dirty
+ tablespaces during apply log */
+ if (!recv_is_making_a_backup) {
+ recv_spaces.insert(std::make_pair(space_id,
+ file_name_t(abs_file_path,
+ false)));
+ }
+ break;
+ case MLOG_FILE_DELETE:
+ /* Don't validate tablespaces while copying redo logs
+ because backup process might keep some tablespace handles
+ open in server datadir. */
+ if (recv_is_making_a_backup)
+ break;
+
+ fil_name_process(
+ name, len, space_id, true);
+
+ if (apply && recv_replay_file_ops
+ && fil_space_get(space_id)) {
+ dberr_t err = fil_delete_tablespace(
+ space_id, BUF_REMOVE_FLUSH_NO_WRITE);
+ ut_a(err == DB_SUCCESS);
+ }
+
+ break;
+ case MLOG_FILE_CREATE2:
+ if (recv_is_making_a_backup
+ || (!recv_replay_file_ops)
+ || (is_intermediate_file(abs_file_path.c_str()))
+ || (fil_space_get(space_id))
+ || (fil_space_get_id_by_name(
+ tablespace_name.c_str()) != ULINT_UNDEFINED)) {
+ /* Don't create table while :-
+ 1. scanning the redo logs during backup
+ 2. apply-log on a partial backup
+ 3. if it is intermediate file
+ 4. tablespace is already loaded in memory */
+ } else {
+ itr = recv_spaces.find(space_id);
+ if (itr == recv_spaces.end()
+ || (itr->second.name != abs_file_path)) {
+
+ dberr_t ret = fil_ibd_create(
+ space_id, tablespace_name.c_str(),
+ abs_file_path.c_str(),
+ flags, FIL_IBD_FILE_INITIAL_SIZE);
+
+ if (ret != DB_SUCCESS) {
+ ib::fatal() << "Could not create the"
+ << " tablespace : "
+ << abs_file_path
+ << " with space Id : "
+ << space_id;
+ }
+ }
+ }
+ break;
+ case MLOG_FILE_RENAME2:
+ /* The new name follows the old name. */
+ byte* new_table_name = end_ptr + 2;
+ if (end < new_table_name) {
+ return(NULL);
+ }
+
+ ulint new_len = mach_read_from_2(end_ptr);
+
+ if (end < end_ptr + 2 + new_len) {
+ return(NULL);
+ }
+
+ end_ptr += 2 + new_len;
+
+ char* new_table = reinterpret_cast<char*>(new_table_name);
+ os_normalize_path(new_table);
+
+ corrupt = corrupt
+ || new_len < sizeof "/a.ibd\0"
+ || memcmp(new_table_name + new_len - 5, DOT_IBD, 5) != 0
+ || !memchr(new_table_name, OS_PATH_SEPARATOR, new_len);
+
+ if (corrupt) {
+ recv_sys->found_corrupt_log = true;
+ break;
+ }
+
+ if (recv_is_making_a_backup
+ || (!recv_replay_file_ops)
+ || (is_intermediate_file(name))
+ || (is_intermediate_file(new_table))) {
+ /* Don't rename table while :-
+ 1. scanning the redo logs during backup
+ 2. apply-log on a partial backup
+ 3. The new name is already used.
+ 4. A tablespace is not open in memory with the old name.
+ This will prevent unintended renames during recovery. */
+ break;
+ } else {
+ make_abs_file_path(new_table, abs_file_path,
+ tablespace_name);
+
+ new_name = static_cast<char*>(ut_malloc_nokey(
+ (abs_file_path.length() + 1)));
+ strcpy(new_name, abs_file_path.c_str());
+ new_len = strlen(new_name) + 1;
+ }
+
+ fil_name_process(name, len, space_id, false);
+ fil_name_process( new_name, new_len, space_id, false);
+
+ if (!fil_op_replay_rename(
+ space_id, first_page_no,
+ name,
+ new_name)) {
+ recv_sys->found_corrupt_fs = true;
+ }
+ }
+
+ if (!recv_is_making_a_backup) {
+ ut_free(name);
+ ut_free(new_name);
+ }
+ return(end_ptr);
+}
+#endif /* UNIV_HOTBACKUP */
/********************************************************//**
Creates the recovery system. */
@@ -507,7 +829,7 @@ recv_sys_close(void)
if (recv_sys->heap != NULL) {
mem_heap_free(recv_sys->heap);
}
-
+#ifndef UNIV_HOTBACKUP
if (recv_sys->flush_start != NULL) {
os_event_destroy(recv_sys->flush_start);
}
@@ -515,7 +837,7 @@ recv_sys_close(void)
if (recv_sys->flush_end != NULL) {
os_event_destroy(recv_sys->flush_end);
}
-
+#endif /* !UNIV_HOTBACKUP */
ut_free(recv_sys->buf);
ut_free(recv_sys->last_block_buf_start);
@@ -547,7 +869,7 @@ recv_sys_mem_free(void)
if (recv_sys->heap != NULL) {
mem_heap_free(recv_sys->heap);
}
-
+#ifndef UNIV_HOTBACKUP
if (recv_sys->flush_start != NULL) {
os_event_destroy(recv_sys->flush_start);
}
@@ -555,7 +877,7 @@ recv_sys_mem_free(void)
if (recv_sys->flush_end != NULL) {
os_event_destroy(recv_sys->flush_end);
}
-
+#endif /* !UNIV_HOTBACKUP */
ut_free(recv_sys->buf);
ut_free(recv_sys->last_block_buf_start);
ut_free(recv_sys);
@@ -636,7 +958,7 @@ DECLARE_THREAD(recv_writer_thread)(
/* We count the number of threads in os_thread_exit().
A created thread should always use that to exit and not
use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -701,14 +1023,14 @@ recv_sys_init(
/* Call the constructor for recv_sys_t::dblwr member */
new (&recv_sys->dblwr) recv_dblwr_t();
+ recv_sys->encryption_list = NULL;
mutex_exit(&(recv_sys->mutex));
}
/********************************************************//**
-Empties the hash table when it has been fully processed.
-@return DB_SUCCESS when successfull or DB_ERROR when fails. */
+Empties the hash table when it has been fully processed.*/
static
-dberr_t
+void
recv_sys_empty_hash(void)
/*=====================*/
{
@@ -717,15 +1039,12 @@ recv_sys_empty_hash(void)
if (recv_sys->n_addrs != 0) {
ib::fatal() << recv_sys->n_addrs << " pages with log records"
" were left unprocessed!";
- return DB_ERROR;
}
hash_table_free(recv_sys->addr_hash);
mem_heap_empty(recv_sys->heap);
recv_sys->addr_hash = hash_create(buf_pool_get_curr_size() / 512);
-
- return DB_SUCCESS;
}
#ifndef UNIV_HOTBACKUP
@@ -756,6 +1075,28 @@ recv_sys_debug_free(void)
os_event_set(recv_sys->flush_start);
}
+ if (recv_sys->encryption_list != NULL) {
+ encryption_list_t::iterator it;
+
+ for (it = recv_sys->encryption_list->begin();
+ it != recv_sys->encryption_list->end();
+ it++) {
+ if (it->key != NULL) {
+ ut_free(it->key);
+ it->key = NULL;
+ }
+ if (it->iv != NULL) {
+ ut_free(it->iv);
+ it->iv = NULL;
+ }
+ }
+
+ recv_sys->encryption_list->swap(*recv_sys->encryption_list);
+
+ UT_DELETE(recv_sys->encryption_list);
+ recv_sys->encryption_list = NULL;
+ }
+
mutex_exit(&(recv_sys->mutex));
}
@@ -824,7 +1165,7 @@ recv_check_log_header_checksum(
@param[out] max_group log group, or NULL
@param[out] max_field LOG_CHECKPOINT_1 or LOG_CHECKPOINT_2
@return error code or DB_SUCCESS */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
recv_find_max_checkpoint_0(
log_group_t** max_group,
@@ -873,6 +1214,11 @@ recv_find_max_checkpoint_0(
checkpoint_no = mach_read_from_8(
buf + LOG_CHECKPOINT_NO);
+ if (!log_crypt_read_checkpoint_buf(buf)) {
+ ib::error() << "Reading checkpoint encryption info failed.";
+ return DB_ERROR;
+ }
+
DBUG_PRINT("ib_log",
("checkpoint " UINT64PF " at " LSN_PF
" found in group " ULINTPF,
@@ -927,7 +1273,7 @@ recv_log_format_0_recover(lsn_t lsn)
univ_page_size,
(ulint) ((source_offset & ~(OS_FILE_LOG_BLOCK_SIZE - 1))
% univ_page_size.physical()),
- OS_FILE_LOG_BLOCK_SIZE, buf, NULL, NULL);
+ OS_FILE_LOG_BLOCK_SIZE, buf, NULL, NULL);
if (log_block_calc_checksum_format_0(buf)
!= log_block_get_checksum(buf)) {
@@ -961,7 +1307,7 @@ recv_log_format_0_recover(lsn_t lsn)
@param[out] max_group log group, or NULL
@param[out] max_field LOG_CHECKPOINT_1 or LOG_CHECKPOINT_2
@return error code or DB_SUCCESS */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
recv_find_max_checkpoint(
log_group_t** max_group,
@@ -1118,14 +1464,12 @@ recv_read_checkpoint_info_for_backup(
cp_buf = hdr + max_cp;
*lsn = mach_read_from_8(cp_buf + LOG_CHECKPOINT_LSN);
- *offset = mach_read_from_4(
- cp_buf + LOG_CHECKPOINT_OFFSET_LOW32);
- *offset |= ((lsn_t) mach_read_from_4(
- cp_buf + LOG_CHECKPOINT_OFFSET_HIGH32)) << 32;
+ *offset = mach_read_from_8(
+ cp_buf + LOG_CHECKPOINT_OFFSET);
*cp_no = mach_read_from_8(cp_buf + LOG_CHECKPOINT_NO);
- *first_header_lsn = mach_read_from_8(hdr + LOG_FILE_START_LSN);
+ *first_header_lsn = mach_read_from_8(hdr + LOG_HEADER_START_LSN);
return(TRUE);
}
@@ -1135,19 +1479,18 @@ recv_read_checkpoint_info_for_backup(
block.
@param[in] log block
@return whether the checksum matches */
-ibool
+bool
log_block_checksum_is_ok(
-/*=====================*/
const byte* block, /*!< in: pointer to a log block */
bool print_err) /*!< in print error ? */
{
if (log_block_get_checksum(block) != log_block_calc_checksum(block) &&
print_err) {
- fprintf(stderr, "BROKEN: block: %lu checkpoint: %lu %.8lx %.8lx\n",
- log_block_get_hdr_no(block),
- log_block_get_checkpoint_no(block),
- log_block_calc_checksum(block),
- log_block_get_checksum(block));
+ ib::error() << " Log block checkpoint not correct."
+ << " block: " << log_block_get_hdr_no(block)
+ << " checkpoint no: " << log_block_get_checkpoint_no(block)
+ << " calc checkpoint: " << log_block_calc_checksum(block)
+ << " stored checkpoint: " << log_block_get_checksum(block);
}
return(!innodb_log_checksums
@@ -1246,6 +1589,116 @@ recv_scan_log_seg_for_backup(
}
#endif /* UNIV_HOTBACKUP */
+#ifdef MYSQL_ENCRYPTION
+
+/** Parse or process a write encryption info record.
+@param[in] ptr redo log record
+@param[in] end end of the redo log buffer
+@param[in] space_id the tablespace ID
+@return log record end, NULL if not a complete record */
+static
+byte*
+fil_write_encryption_parse(
+ byte* ptr,
+ const byte* end,
+ ulint space_id)
+{
+ fil_space_t* space;
+ ulint offset;
+ ulint len;
+ byte* key = NULL;
+ byte* iv = NULL;
+ bool is_new = false;
+
+ space = fil_space_get(space_id);
+ if (space == NULL) {
+ encryption_list_t::iterator it;
+
+ if (recv_sys->encryption_list == NULL) {
+ recv_sys->encryption_list =
+ UT_NEW_NOKEY(encryption_list_t());
+ }
+
+ for (it = recv_sys->encryption_list->begin();
+ it != recv_sys->encryption_list->end();
+ it++) {
+ if (it->space_id == space_id) {
+ key = it->key;
+ iv = it->iv;
+ }
+ }
+
+ if (key == NULL) {
+ key = static_cast<byte*>(ut_malloc_nokey(
+ ENCRYPTION_KEY_LEN));
+ iv = static_cast<byte*>(ut_malloc_nokey(
+ ENCRYPTION_KEY_LEN));
+ is_new = true;
+ }
+ } else {
+ key = space->encryption_key;
+ iv = space->encryption_iv;
+ }
+
+ offset = mach_read_from_2(ptr);
+ ptr += 2;
+ len = mach_read_from_2(ptr);
+
+ ptr += 2;
+ if (end < ptr + len) {
+ return(NULL);
+ }
+
+ if (offset >= UNIV_PAGE_SIZE
+ || len + offset > UNIV_PAGE_SIZE
+ || (len != ENCRYPTION_INFO_SIZE_V1
+ && len != ENCRYPTION_INFO_SIZE_V2)) {
+ recv_sys->found_corrupt_log = TRUE;
+ return(NULL);
+ }
+
+#ifdef UNIV_ENCRYPT_DEBUG
+ if (space) {
+ fprintf(stderr, "Got %lu from redo log:", space->id);
+ }
+#endif
+
+ if (!fsp_header_decode_encryption_info(key,
+ iv,
+ ptr)) {
+ recv_sys->found_corrupt_log = TRUE;
+ ib::warn() << "Encryption information"
+ << " in the redo log of space "
+ << space_id << " is invalid";
+ }
+
+ ut_ad(len == ENCRYPTION_INFO_SIZE_V1
+ || len == ENCRYPTION_INFO_SIZE_V2);
+
+ ptr += len;
+
+ if (space == NULL) {
+ if (is_new) {
+ recv_encryption_t info;
+
+ /* Add key and iv to list */
+ info.space_id = space_id;
+ info.key = key;
+ info.iv = iv;
+
+ recv_sys->encryption_list->push_back(info);
+ }
+ } else {
+ ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags));
+
+ space->encryption_type = Encryption::AES;
+ space->encryption_klen = ENCRYPTION_KEY_LEN;
+ }
+
+ return(ptr);
+}
+#endif /* MYSQL_ENCRYPTION */
+
/** Try to parse a single log record body and also applies it if
specified.
@param[in] type redo log entry type
@@ -1273,7 +1726,9 @@ recv_parse_or_apply_log_rec_body(
mtr_t* mtr)
{
ut_ad(!block == !mtr);
+#ifndef UNIV_HOTBACKUP
ut_ad(!apply || recv_sys->mlog_checkpoint_lsn != 0);
+#endif /* !UNIV_HOTBACKUP */
switch (type) {
case MLOG_FILE_NAME:
@@ -1286,12 +1741,87 @@ recv_parse_or_apply_log_rec_body(
return(fil_name_parse(ptr, end_ptr, space_id, page_no, type,
apply));
case MLOG_INDEX_LOAD:
+#ifdef UNIV_HOTBACKUP
+ /* While scaning redo logs during backup phase a
+ MLOG_INDEX_LOAD type redo log record indicates a DDL
+ (create index, alter table...)is performed with
+ 'algorithm=inplace'. This redo log indicates that
+
+ 1. The DDL was started after MEB started backing up, in which
+ case MEB will not be able to take a consistent backup and should
+ fail. or
+ 2. There is a possibility of this record existing in the REDO
+ even after the completion of the index create operation. This is
+ because of InnoDB does not checkpointing after the flushing the
+ index pages.
+
+ If MEB gets the last_redo_flush_lsn and that is less than the
+ lsn of the current record MEB fails the backup process.
+ Error out in case of online backup and emit a warning in case
+ of offline backup and continue.
+ */
+ if (!recv_recovery_on) {
+ if (is_online_redo_copy) {
+ if (backup_redo_log_flushed_lsn
+ < recv_sys->recovered_lsn) {
+ ib::trace() << "Last flushed lsn: "
+ << backup_redo_log_flushed_lsn
+ << " load_index lsn "
+ << recv_sys->recovered_lsn;
+
+ if (backup_redo_log_flushed_lsn == 0)
+ ib::error() << "MEB was not "
+ "able to determine the"
+ "InnoDB Engine Status";
+
+ ib::fatal() << "An optimized(without"
+ " redo logging) DDLoperation"
+ " has been performed. All"
+ " modified pages may not have"
+ " been flushed to the disk yet."
+ " \n MEB will not be able"
+ " take a consistent backup."
+ " Retry the backup operation";
+ }
+ /** else the index is flushed to disk before
+ backup started hence no error */
+ } else {
+ /* offline backup */
+ ib::trace() << "Last flushed lsn: "
+ << backup_redo_log_flushed_lsn
+ << " load_index lsn "
+ << recv_sys->recovered_lsn;
+
+ ib::warn() << "An optimized(without redo"
+ " logging) DDL operation has been"
+ " performed. All modified pages may not"
+ " have been flushed to the disk yet."
+ " \n This offline backup may not"
+ " be consistent";
+ }
+ }
+#endif /* UNIV_HOTBACKUP */
if (end_ptr < ptr + 8) {
return(NULL);
}
return(ptr + 8);
case MLOG_TRUNCATE:
return(truncate_t::parse_redo_entry(ptr, end_ptr, space_id));
+ case MLOG_WRITE_STRING:
+ /* For encrypted tablespace, we need to get the
+ encryption key information before the page 0 is recovered.
+ Otherwise, redo will not find the key to decrypt
+ the data pages. */
+#ifdef MYSQL_ENCRYPTION
+ if (page_no == 0 && !is_system_tablespace(space_id)
+ && !apply) {
+ return(fil_write_encryption_parse(ptr,
+ end_ptr,
+ space_id));
+ }
+#endif
+ break;
+
default:
break;
}
@@ -1333,7 +1863,80 @@ recv_parse_or_apply_log_rec_body(
break;
#endif /* UNIV_LOG_LSN_DEBUG */
case MLOG_1BYTE: case MLOG_2BYTES: case MLOG_4BYTES: case MLOG_8BYTES:
- /* Note that crypt data can be set to empty page */
+#ifdef UNIV_DEBUG
+ if (page && page_type == FIL_PAGE_TYPE_ALLOCATED
+ && end_ptr >= ptr + 2) {
+ /* It is OK to set FIL_PAGE_TYPE and certain
+ list node fields on an empty page. Any other
+ write is not OK. */
+
+ /* NOTE: There may be bogus assertion failures for
+ dict_hdr_create(), trx_rseg_header_create(),
+ trx_sys_create_doublewrite_buf(), and
+ trx_sysf_create().
+ These are only called during database creation. */
+ ulint offs = mach_read_from_2(ptr);
+
+ switch (type) {
+ default:
+ ut_error;
+ case MLOG_2BYTES:
+ /* Note that this can fail when the
+ redo log been written with something
+ older than InnoDB Plugin 1.0.4. */
+ ut_ad(offs == FIL_PAGE_TYPE
+ || offs == IBUF_TREE_SEG_HEADER
+ + IBUF_HEADER + FSEG_HDR_OFFSET
+ || offs == PAGE_BTR_IBUF_FREE_LIST
+ + PAGE_HEADER + FIL_ADDR_BYTE
+ || offs == PAGE_BTR_IBUF_FREE_LIST
+ + PAGE_HEADER + FIL_ADDR_BYTE
+ + FIL_ADDR_SIZE
+ || offs == PAGE_BTR_SEG_LEAF
+ + PAGE_HEADER + FSEG_HDR_OFFSET
+ || offs == PAGE_BTR_SEG_TOP
+ + PAGE_HEADER + FSEG_HDR_OFFSET
+ || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
+ + PAGE_HEADER + FIL_ADDR_BYTE
+ + 0 /*FLST_PREV*/
+ || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
+ + PAGE_HEADER + FIL_ADDR_BYTE
+ + FIL_ADDR_SIZE /*FLST_NEXT*/);
+ break;
+ case MLOG_4BYTES:
+ /* Note that this can fail when the
+ redo log been written with something
+ older than InnoDB Plugin 1.0.4. */
+ ut_ad(0
+ || offs == IBUF_TREE_SEG_HEADER
+ + IBUF_HEADER + FSEG_HDR_SPACE
+ || offs == IBUF_TREE_SEG_HEADER
+ + IBUF_HEADER + FSEG_HDR_PAGE_NO
+ || offs == PAGE_BTR_IBUF_FREE_LIST
+ + PAGE_HEADER/* flst_init */
+ || offs == PAGE_BTR_IBUF_FREE_LIST
+ + PAGE_HEADER + FIL_ADDR_PAGE
+ || offs == PAGE_BTR_IBUF_FREE_LIST
+ + PAGE_HEADER + FIL_ADDR_PAGE
+ + FIL_ADDR_SIZE
+ || offs == PAGE_BTR_SEG_LEAF
+ + PAGE_HEADER + FSEG_HDR_PAGE_NO
+ || offs == PAGE_BTR_SEG_LEAF
+ + PAGE_HEADER + FSEG_HDR_SPACE
+ || offs == PAGE_BTR_SEG_TOP
+ + PAGE_HEADER + FSEG_HDR_PAGE_NO
+ || offs == PAGE_BTR_SEG_TOP
+ + PAGE_HEADER + FSEG_HDR_SPACE
+ || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
+ + PAGE_HEADER + FIL_ADDR_PAGE
+ + 0 /*FLST_PREV*/
+ || offs == PAGE_BTR_IBUF_FREE_LIST_NODE
+ + PAGE_HEADER + FIL_ADDR_PAGE
+ + FIL_ADDR_SIZE /*FLST_NEXT*/);
+ break;
+ }
+ }
+#endif /* UNIV_DEBUG */
ptr = mlog_parse_nbytes(type, ptr, end_ptr, page, page_zip);
if (ptr != NULL && page != NULL
&& page_no == 0 && type == MLOG_4BYTES) {
@@ -1542,7 +2145,6 @@ recv_parse_or_apply_log_rec_body(
ptr = fsp_parse_init_file_page(ptr, end_ptr, block);
break;
case MLOG_WRITE_STRING:
- /* Allow setting crypt_data also for empty page */
ptr = mlog_parse_string(ptr, end_ptr, page, page_zip);
break;
case MLOG_ZIP_WRITE_NODE_PTR:
@@ -1799,9 +2401,6 @@ recv_recover_page_func(
lsn_t end_lsn;
lsn_t page_lsn;
lsn_t page_newest_lsn;
-#ifdef UNIV_DEBUG
- lsn_t max_lsn;
-#endif /* UNIV_DEBUG */
ibool modification_to_page;
mtr_t mtr;
@@ -1829,12 +2428,13 @@ recv_recover_page_func(
return;
}
+#ifndef UNIV_HOTBACKUP
ut_ad(recv_needed_recovery);
- ut_d(max_lsn = UT_LIST_GET_FIRST(log_sys->log_groups)->scanned_lsn);
DBUG_PRINT("ib_log",
("Applying log to page %u:%u",
recv_addr->space, recv_addr->page_no));
+#endif /* !UNIV_HOTBACKUP */
recv_addr->state = RECV_BEING_PROCESSED;
@@ -1890,7 +2490,8 @@ recv_recover_page_func(
while (recv) {
end_lsn = recv->end_lsn;
- ut_ad(end_lsn <= max_lsn);
+ ut_ad(end_lsn
+ <= UT_LIST_GET_FIRST(log_sys->log_groups)->scanned_lsn);
if (recv->len > RECV_DATA_BLOCK_SIZE) {
/* We have to copy the record body to a separate
@@ -1925,7 +2526,7 @@ recv_recover_page_func(
Note: We can't skip complete recv_addr as same page may have
valid REDO records post truncate those needs to be applied. */
bool skip_recv = false;
- if (srv_was_tablespace_truncated(recv_addr->space)) {
+ if (srv_was_tablespace_truncated(fil_space_get(recv_addr->space))) {
lsn_t init_lsn =
truncate_t::get_truncated_tablespace_init_lsn(
recv_addr->space);
@@ -2000,6 +2601,8 @@ recv_recover_page_func(
buf_flush_recv_note_modification(block, start_lsn, end_lsn);
log_flush_order_mutex_exit();
}
+#else /* !UNIV_HOTBACKUP */
+ start_lsn = start_lsn; /* Silence compiler */
#endif /* !UNIV_HOTBACKUP */
/* Make sure that committing mtr does not change the modification
@@ -2095,8 +2698,8 @@ recv_apply_hashed_log_recs(
recv_addr_t* recv_addr;
ulint i;
ibool has_printed = FALSE;
- ulong progress;
mtr_t mtr;
+ ulint progress = 0;
dberr_t err = DB_SUCCESS;
loop:
mutex_enter(&(recv_sys->mutex));
@@ -2185,10 +2788,11 @@ loop:
}
}
- progress = (ulong) (i * 100)
- / hash_get_n_cells(recv_sys->addr_hash);
+ progress = (ulint) ((i * 100) / hash_get_n_cells(recv_sys->addr_hash));
+
if (has_printed
&& progress
+ && (i * 100) / hash_get_n_cells(recv_sys->addr_hash)
!= ((i + 1) * 100)
/ hash_get_n_cells(recv_sys->addr_hash)) {
@@ -2250,7 +2854,7 @@ loop:
recv_sys->apply_log_recs = FALSE;
recv_sys->apply_batch_on = FALSE;
- err = recv_sys_empty_hash();
+ recv_sys_empty_hash();
if (has_printed) {
ib::info() << "Apply batch completed";
@@ -2274,14 +2878,15 @@ recv_apply_log_recs_for_backup(void)
bool success;
ulint error;
ulint i;
-
+ fil_space_t* space = NULL;
+ page_id_t page_id;
recv_sys->apply_log_recs = TRUE;
recv_sys->apply_batch_on = TRUE;
block = back_block1;
ib::info() << "Starting an apply batch of log records to the"
- " database...";
+ " database...\n";
fputs("InnoDB: Progress in percent: ", stderr);
@@ -2289,10 +2894,16 @@ recv_apply_log_recs_for_backup(void)
for (i = 0; i < n_hash_cells; i++) {
/* The address hash table is externally chained */
- recv_addr = hash_get_nth_cell(recv_sys->addr_hash, i)->node;
+ recv_addr = static_cast<recv_addr_t*>(hash_get_nth_cell(
+ recv_sys->addr_hash, i)->node);
while (recv_addr != NULL) {
+ ib::trace() << "recv_addr {State: " << recv_addr->state
+ << ", Space id: " << recv_addr->space
+ << "Page no: " << recv_addr->page_no
+ << ". index i: " << i << "\n";
+
bool found;
const page_size_t& page_size
= fil_space_get_page_size(recv_addr->space,
@@ -2379,7 +2990,8 @@ recv_apply_log_recs_for_backup(void)
fil0fil.cc routines */
buf_flush_init_for_writing(
- block->frame, buf_block_get_page_zip(block),
+ block, block->frame,
+ buf_block_get_page_zip(block),
mach_read_from_8(block->frame + FIL_PAGE_LSN),
fsp_is_checksum_disabled(
block->page.id.space()));
@@ -2397,21 +3009,27 @@ recv_apply_log_recs_for_backup(void)
block->frame, NULL);
}
skip_this_recv_addr:
- recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
+ recv_addr = static_cast<recv_addr_t*>(HASH_GET_NEXT(
+ addr_hash, recv_addr));
}
if ((100 * i) / n_hash_cells
!= (100 * (i + 1)) / n_hash_cells) {
fprintf(stderr, "%lu ",
- (ulong) ((100 * i) / n_hash_cells));
+ (ulint) ((100 * i) / n_hash_cells));
fflush(stderr);
sd_notifyf(0, "STATUS=Applying batch of log records for"
" backup InnoDB: Progress %lu",
- (ulong) (100 * i) / n_hash_cells);
+ (ulint) (100 * i) / n_hash_cells);
}
}
+
sd_notify(0, "STATUS=InnoDB: Apply batch for backup completed");
+ /* write logs in next line */
+ fprintf(stderr, "\n");
+ recv_sys->apply_log_recs = FALSE;
+ recv_sys->apply_batch_on = FALSE;
recv_sys_empty_hash();
}
#endif /* !UNIV_HOTBACKUP */
@@ -2479,7 +3097,6 @@ recv_parse_log_rec(
case MLOG_DUMMY_RECORD | MLOG_SINGLE_REC_FLAG:
case MLOG_CHECKPOINT | MLOG_SINGLE_REC_FLAG:
ib::error() << "Incorrect log record type:" << *ptr;
-
recv_sys->found_corrupt_log = true;
return(0);
}
@@ -2602,16 +3219,16 @@ hash table to wait merging to file pages.
@param[in] checkpoint_lsn the LSN of the latest checkpoint
@param[in] store whether to store page operations
@param[in] apply whether to apply the records
-@param[out] err DB_SUCCESS if successfull
+@param[out] err DB_SUCCESS or error code
@return whether MLOG_CHECKPOINT record was seen the first time,
or corruption was noticed */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
recv_parse_log_recs(
lsn_t checkpoint_lsn,
store_t store,
bool apply,
- dberr_t* err)
+ dberr_t* err)
{
byte* ptr;
byte* end_ptr;
@@ -2723,7 +3340,9 @@ loop:
}
recv_sys->mlog_checkpoint_lsn
= recv_sys->recovered_lsn;
+#ifndef UNIV_HOTBACKUP
return(true);
+#endif /* !UNIV_HOTBACKUP */
}
break;
case MLOG_FILE_NAME:
@@ -2761,11 +3380,11 @@ loop:
/* fall through */
case MLOG_INDEX_LOAD:
DBUG_PRINT("ib_log",
- ("scan " LSN_PF ": log rec %s"
- " len " ULINTPF
- " page " ULINTPF ":" ULINTPF,
- old_lsn, get_mlog_string(type),
- len, space, page_no));
+ ("scan " LSN_PF ": log rec %s"
+ " len " ULINTPF
+ " page " ULINTPF ":" ULINTPF,
+ old_lsn, get_mlog_string(type),
+ len, space, page_no));
}
} else {
/* Check that all the records associated with the single mtr
@@ -3038,8 +3657,8 @@ recv_scan_log_recs(
bool finished = false;
ulint data_len;
bool more_data = false;
- bool maybe_encrypted=false;
bool apply = recv_sys->mlog_checkpoint_lsn != 0;
+ bool maybe_encrypted = false;
ut_ad(start_lsn % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_ad(len % OS_FILE_LOG_BLOCK_SIZE == 0);
@@ -3048,12 +3667,10 @@ recv_scan_log_recs(
do {
ut_ad(!finished);
-
no = log_block_get_hdr_no(log_block);
ulint expected_no = log_block_convert_lsn_to_no(scanned_lsn);
if (no != expected_no) {
/* Garbage or an incompletely written log block.
- log_crypt_err_t log_crypt_err;
We will not report any error, because this can
happen when InnoDB was killed while it was
@@ -3065,6 +3682,7 @@ recv_scan_log_recs(
if (!log_block_checksum_is_ok(log_block, true)) {
log_crypt_err_t log_crypt_err;
+
maybe_encrypted = log_crypt_block_maybe_encrypted(log_block,
&log_crypt_err);
@@ -3083,8 +3701,8 @@ recv_scan_log_recs(
<< log_block_get_checksum(log_block)
<< ", should be "
<< log_block_calc_checksum(log_block);
-
/* Garbage or an incompletely written log block.
+
This could be the result of killing the server
while it was writing this log block. We treat
this as an abrupt end of the redo log. */
@@ -3176,7 +3794,7 @@ recv_scan_log_recs(
<< "Set innodb_force_recovery"
" to ignore this error.";
*err = DB_ERROR;
- return (true);
+ return(true);
}
#endif /* !UNIV_HOTBACKUP */
@@ -3259,6 +3877,7 @@ Parses and hashes the log records if new data found.
until which all redo log has been scanned
@param[in] last_phase whether changes
can be applied to the tablespaces
+@param[out] err DB_SUCCESS or error code
@return whether rescan is needed (not everything was stored) */
static
bool
@@ -3266,7 +3885,7 @@ recv_group_scan_log_recs(
log_group_t* group,
lsn_t* contiguous_lsn,
bool last_phase,
- dberr_t* err) /*!< out: error code or DB_SUCCESS */
+ dberr_t* err)
{
DBUG_ENTER("recv_group_scan_log_recs");
DBUG_ASSERT(!last_phase || recv_sys->mlog_checkpoint_lsn > 0);
@@ -3327,6 +3946,8 @@ recv_group_scan_log_recs(
start_lsn, contiguous_lsn, &group->scanned_lsn, err));
if (recv_sys->found_corrupt_log || recv_sys->found_corrupt_fs) {
+ ib::error() << "Found corrupted log when looking checkpoint lsn: "
+ << contiguous_lsn << " error = " << *err;
DBUG_RETURN(false);
}
@@ -3381,7 +4002,7 @@ recv_init_missing_space(dberr_t err, const recv_spaces_t::const_iterator& i)
/** Check if all tablespaces were found for crash recovery.
@return error code or DB_SUCCESS */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
recv_init_crash_recovery_spaces(void)
{
@@ -3543,7 +4164,7 @@ recv_recovery_from_checkpoint_start(
const page_id_t page_id(max_cp_group->space_id, 0);
fil_io(IORequestLogRead, true, page_id, univ_page_size, 0,
- LOG_FILE_HDR_SIZE, log_hdr_buf, max_cp_group, NULL);
+ LOG_FILE_HDR_SIZE, log_hdr_buf, max_cp_group, NULL);
if (0 == ut_memcmp(log_hdr_buf + LOG_HEADER_CREATOR,
(byte*)"ibbackup", (sizeof "ibbackup") - 1)) {
@@ -3577,12 +4198,13 @@ recv_recovery_from_checkpoint_start(
/* Write to the log file to wipe over the label */
fil_io(IORequestLogWrite, true, page_id,
univ_page_size, 0, OS_FILE_LOG_BLOCK_SIZE, log_hdr_buf,
- max_cp_group, NULL);
+ max_cp_group, NULL);
}
/* Start reading the log groups from the checkpoint lsn up. The
variable contiguous_lsn contains an lsn up to which the log is
known to be contiguously written to all log groups. */
+
recv_sys->mlog_checkpoint_lsn = 0;
ut_ad(RECV_SCAN_SIZE <= log_sys->buf_size);
@@ -3613,7 +4235,6 @@ recv_recovery_from_checkpoint_start(
if (recv_sys->found_corrupt_log && !srv_force_recovery) {
log_mutex_exit();
-
ib::error() << "Found corrupted log when looking checkpoint lsn: "
<< contiguous_lsn << " error = " << err;
return(DB_ERROR);
@@ -3680,6 +4301,7 @@ recv_recovery_from_checkpoint_start(
recv_init_crash_recovery();
}
}
+
log_sys->lsn = recv_sys->recovered_lsn;
if (recv_needed_recovery) {
@@ -3692,6 +4314,7 @@ recv_recovery_from_checkpoint_start(
if (rescan) {
contiguous_lsn = checkpoint_lsn;
+
recv_group_scan_log_recs(group, &contiguous_lsn, true, &err);
if ((recv_sys->found_corrupt_log
@@ -3700,6 +4323,7 @@ recv_recovery_from_checkpoint_start(
log_mutex_exit();
ib::error() << "Found corrupted log in lsn:"
<< contiguous_lsn << " err = " << err;
+
return(DB_ERROR);
}
}
@@ -3722,12 +4346,13 @@ recv_recovery_from_checkpoint_start(
if (recv_sys->recovered_lsn < checkpoint_lsn) {
log_mutex_exit();
+ ib::error() << "Recovered only to lsn:"
+ << recv_sys->recovered_lsn << " checkpoint_lsn: " << checkpoint_lsn;
+
/* No harm in trying to do RO access. */
if (!srv_read_only_mode) {
- return (DB_READ_ONLY);
+ ut_error;
}
- ib::error() << "Recovered only to lsn:"
- << recv_sys->recovered_lsn << " checkpoint_lsn: " << checkpoint_lsn;
return(DB_ERROR);
}
@@ -3737,6 +4362,7 @@ recv_recovery_from_checkpoint_start(
log_sys->next_checkpoint_lsn = checkpoint_lsn;
log_sys->next_checkpoint_no = checkpoint_no + 1;
+
/* here the checkpoint info is written without any redo logging ongoing
* and next_checkpoint_no is updated directly hence no +1 */
log_crypt_set_ver_and_key(log_sys->next_checkpoint_no);
@@ -3972,12 +4598,13 @@ recv_reset_log_files_for_backup(
*/
ut_a(log_dir_len + strlen(ib_logfile_basename) + 11 < sizeof(name));
- buf = ut_zalloc_nokey(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
+ buf = (byte*)ut_zalloc_nokey(LOG_FILE_HDR_SIZE +
+ OS_FILE_LOG_BLOCK_SIZE);
for (i = 0; i < n_log_files; i++) {
sprintf(name, "%s%s%lu", log_dir,
- ib_logfile_basename, (ulong) i);
+ ib_logfile_basename, (ulint) i);
log_file = os_file_create_simple(innodb_log_file_key,
name, OS_FILE_CREATE,
@@ -3995,7 +4622,7 @@ recv_reset_log_files_for_backup(
if (!success) {
ib::fatal() << "Cannot set " << name << " size to "
- << log_file_size;
+ << (long long unsigned)log_file_size;
}
os_file_flush(log_file);
@@ -4006,10 +4633,14 @@ recv_reset_log_files_for_backup(
log_reset_first_header_and_checkpoint(buf, lsn);
- log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn);
+ log_block_init(buf + LOG_FILE_HDR_SIZE, lsn);
log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE,
LOG_BLOCK_HDR_SIZE);
- sprintf(name, "%s%s%lu", log_dir, ib_logfile_basename, (ulong)0);
+ log_block_set_checksum(buf + LOG_FILE_HDR_SIZE,
+ log_block_calc_checksum_crc32(buf + LOG_FILE_HDR_SIZE));
+
+ log_block_set_checksum(buf, log_block_calc_checksum_crc32(buf));
+ sprintf(name, "%s%s%lu", log_dir, ib_logfile_basename, (ulint)0);
log_file = os_file_create_simple(innodb_log_file_key,
name, OS_FILE_OPEN,
diff --git a/storage/innobase/mtr/mtr0log.cc b/storage/innobase/mtr/mtr0log.cc
index 944937879c2..d653b3851c3 100644
--- a/storage/innobase/mtr/mtr0log.cc
+++ b/storage/innobase/mtr/mtr0log.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -151,11 +151,6 @@ mlog_parse_nbytes(
offset = mach_read_from_2(ptr);
ptr += 2;
- ut_a(!page || !page_zip || fil_page_get_type(page) != FIL_PAGE_INDEX ||
- /* scrubbing changes page type from FIL_PAGE_INDEX to
- * FIL_PAGE_TYPE_ALLOCATED (rest of this assertion is below) */
- (type == MLOG_2BYTES && offset == FIL_PAGE_TYPE));
-
if (offset >= UNIV_PAGE_SIZE) {
recv_sys->found_corrupt_log = TRUE;
@@ -215,13 +210,6 @@ mlog_parse_nbytes(
}
mach_write_to_2(page + offset, val);
}
- ut_a(!page || !page_zip ||
- fil_page_get_type(page) != FIL_PAGE_INDEX ||
- /* scrubbing changes page type from FIL_PAGE_INDEX to
- * FIL_PAGE_TYPE_ALLOCATED */
- (type == MLOG_2BYTES &&
- offset == FIL_PAGE_TYPE &&
- val == FIL_PAGE_TYPE_ALLOCATED));
break;
case MLOG_4BYTES:
diff --git a/storage/innobase/mtr/mtr0mtr.cc b/storage/innobase/mtr/mtr0mtr.cc
index 520608680bb..e8ed8adb483 100644
--- a/storage/innobase/mtr/mtr0mtr.cc
+++ b/storage/innobase/mtr/mtr0mtr.cc
@@ -111,6 +111,67 @@ struct Find {
const void* m_object;
};
+/** Find a page frame */
+struct FindPage
+{
+ /** Constructor
+ @param[in] ptr pointer to within a page frame
+ @param[in] flags MTR_MEMO flags to look for */
+ FindPage(const void* ptr, ulint flags)
+ : m_ptr(ptr), m_flags(flags), m_slot(NULL)
+ {
+ /* We can only look for page-related flags. */
+ ut_ad(!(flags & ~(MTR_MEMO_PAGE_S_FIX
+ | MTR_MEMO_PAGE_X_FIX
+ | MTR_MEMO_PAGE_SX_FIX
+ | MTR_MEMO_BUF_FIX
+ | MTR_MEMO_MODIFY)));
+ }
+
+ /** Visit a memo entry.
+ @param[in] slot memo entry to visit
+ @retval false if a page was found
+ @retval true if the iteration should continue */
+ bool operator()(mtr_memo_slot_t* slot)
+ {
+ ut_ad(m_slot == NULL);
+
+ if (!(m_flags & slot->type) || slot->object == NULL) {
+ return(true);
+ }
+
+ buf_block_t* block = reinterpret_cast<buf_block_t*>(
+ slot->object);
+
+ if (m_ptr < block->frame
+ || m_ptr >= block->frame + block->page.size.logical()) {
+ return(true);
+ }
+
+ m_slot = slot;
+ return(false);
+ }
+
+ /** @return the slot that was found */
+ mtr_memo_slot_t* get_slot() const
+ {
+ ut_ad(m_slot != NULL);
+ return(m_slot);
+ }
+ /** @return the block that was found */
+ buf_block_t* get_block() const
+ {
+ return(reinterpret_cast<buf_block_t*>(get_slot()->object));
+ }
+private:
+ /** Pointer inside a page frame to look for */
+ const void*const m_ptr;
+ /** MTR_MEMO flags to look for */
+ const ulint m_flags;
+ /** The slot corresponding to m_ptr */
+ mtr_memo_slot_t* m_slot;
+};
+
/** Release latches and decrement the buffer fix count.
@param slot memo slot */
static
@@ -180,7 +241,7 @@ memo_block_unfix(mtr_memo_slot_t* slot)
}
/** Release latches represented by a slot.
@param slot memo slot */
-static MY_ATTRIBUTE((nonnull))
+static
void
memo_latch_release(mtr_memo_slot_t* slot)
{
@@ -438,32 +499,7 @@ mtr_write_log(
void
mtr_t::start(bool sync, bool read_only)
{
- UNIV_MEM_INVALID(this, sizeof(*this));
-
- UNIV_MEM_INVALID(&m_impl, sizeof(m_impl));
-
- m_sync = sync;
-
- m_commit_lsn = 0;
-
- new(&m_impl.m_log) mtr_buf_t();
- new(&m_impl.m_memo) mtr_buf_t();
-
- m_impl.m_mtr = this;
- m_impl.m_log_mode = MTR_LOG_ALL;
- m_impl.m_inside_ibuf = false;
- m_impl.m_modifications = false;
- m_impl.m_made_dirty = false;
- m_impl.m_n_log_recs = 0;
- m_impl.m_state = MTR_STATE_ACTIVE;
- ut_d(m_impl.m_user_space_id = TRX_SYS_SPACE);
- m_impl.m_user_space = NULL;
- m_impl.m_undo_space = NULL;
- m_impl.m_sys_space = NULL;
- m_impl.m_flush_observer = NULL;
- m_impl.m_trx = NULL;
-
- ut_d(m_impl.m_magic_n = MTR_MAGIC_N);
+ start(NULL, sync, read_only);
}
/** Start a mini-transaction.
@@ -742,6 +778,31 @@ mtr_t::memo_release(const void* object, ulint type)
return(false);
}
+/** Release a page latch.
+@param[in] ptr pointer to within a page frame
+@param[in] type object type: MTR_MEMO_PAGE_X_FIX, ... */
+void
+mtr_t::release_page(const void* ptr, mtr_memo_type_t type)
+{
+ ut_ad(m_impl.m_magic_n == MTR_MAGIC_N);
+ ut_ad(is_active());
+
+ /* We cannot release a page that has been written to in the
+ middle of a mini-transaction. */
+ ut_ad(!m_impl.m_modifications || type != MTR_MEMO_PAGE_X_FIX);
+
+ FindPage find(ptr, type);
+ Iterate<FindPage> iterator(find);
+
+ if (!m_impl.m_memo.for_each_block_in_reverse(iterator)) {
+ memo_slot_release(find.get_slot());
+ return;
+ }
+
+ /* The page was not found! */
+ ut_ad(0);
+}
+
/** Prepare to write the mini-transaction log to the redo log buffer.
@return number of bytes to write in finish_write() */
ulint
@@ -781,8 +842,6 @@ mtr_t::Command::prepare_write()
log_mutex_enter();
- log_margin_checkpoint_age(len);
-
if (fil_names_write_if_was_clean(space, m_impl->m_mtr)) {
/* This mini-transaction was the first one to modify
this tablespace since the latest checkpoint, so
@@ -816,6 +875,9 @@ mtr_t::Command::prepare_write()
}
}
+ /* check and attempt a checkpoint if exceeding capacity */
+ log_margin_checkpoint_age(len);
+
return(len);
}
@@ -920,6 +982,38 @@ mtr_t::Command::execute()
release_resources();
}
+/** Release the free extents that was reserved using
+fsp_reserve_free_extents(). This is equivalent to calling
+fil_space_release_free_extents(). This is intended for use
+with index pages.
+@param[in] n_reserved number of reserved extents */
+void
+mtr_t::release_free_extents(ulint n_reserved)
+{
+ fil_space_t* space;
+
+ ut_ad(m_impl.m_undo_space == NULL);
+
+ if (m_impl.m_user_space != NULL) {
+
+ ut_ad(m_impl.m_user_space->id
+ == m_impl.m_user_space_id);
+ ut_ad(memo_contains(get_memo(), &m_impl.m_user_space->latch,
+ MTR_MEMO_X_LOCK));
+
+ space = m_impl.m_user_space;
+ } else {
+
+ ut_ad(m_impl.m_sys_space->id == TRX_SYS_SPACE);
+ ut_ad(memo_contains(get_memo(), &m_impl.m_sys_space->latch,
+ MTR_MEMO_X_LOCK));
+
+ space = m_impl.m_sys_space;
+ }
+
+ space->release_free_extents(n_reserved);
+}
+
#ifdef UNIV_DEBUG
/** Check if memo contains the given item.
@return true if contains */
@@ -935,17 +1029,6 @@ mtr_t::memo_contains(
return(!memo->for_each_block_in_reverse(iterator));
}
-/** Check if memo contains the given page.
-@param memo info
-@param ptr record
-@param type type of
-@return true if contains */
-bool
-mtr_t::memo_contains_page(mtr_buf_t* memo, const byte* ptr, ulint type)
-{
- return(memo_contains(memo, buf_block_align(ptr), type));
-}
-
/** Debug check for flags */
struct FlaggedCheck {
FlaggedCheck(const void* ptr, ulint flags)
@@ -987,16 +1070,35 @@ mtr_t::memo_contains_flagged(const void* ptr, ulint flags) const
}
/** Check if memo contains the given page.
-@param ptr buffer frame
-@param flags specify types of object with OR of
+@param[in] ptr pointer to within buffer frame
+@param[in] flags specify types of object with OR of
MTR_MEMO_PAGE_S_FIX... values
-@return true if contains */
-bool
+@return the block
+@retval NULL if not found */
+buf_block_t*
mtr_t::memo_contains_page_flagged(
const byte* ptr,
ulint flags) const
{
- return(memo_contains_flagged(buf_block_align(ptr), flags));
+ FindPage check(ptr, flags);
+ Iterate<FindPage> iterator(check);
+
+ return(m_impl.m_memo.for_each_block_in_reverse(iterator)
+ ? NULL : check.get_block());
+}
+
+/** Mark the given latched page as modified.
+@param[in] ptr pointer to within buffer frame */
+void
+mtr_t::memo_modify_page(const byte* ptr)
+{
+ buf_block_t* block = memo_contains_page_flagged(
+ ptr, MTR_MEMO_PAGE_X_FIX | MTR_MEMO_PAGE_SX_FIX);
+ ut_ad(block != NULL);
+
+ if (!memo_contains(get_memo(), block, MTR_MEMO_MODIFY)) {
+ memo_push(block, MTR_MEMO_MODIFY);
+ }
}
/** Print info of an mtr handle. */
@@ -1009,4 +1111,3 @@ mtr_t::print() const
}
#endif /* UNIV_DEBUG */
-
diff --git a/storage/innobase/os/os0file.cc b/storage/innobase/os/os0file.cc
index 0d63b6c091c..047eec7949c 100644
--- a/storage/innobase/os/os0file.cc
+++ b/storage/innobase/os/os0file.cc
@@ -125,6 +125,30 @@ static const ulint IO_LOG_SEGMENT = 1;
/** Number of retries for partial I/O's */
static const ulint NUM_RETRIES_ON_PARTIAL_IO = 10;
+/** Blocks for doing IO, used in the transparent compression
+and encryption code. */
+struct Block {
+ /** Default constructor */
+ Block() : m_ptr(), m_in_use() { }
+
+ byte* m_ptr;
+
+ byte pad[CACHE_LINE_SIZE - sizeof(ulint)];
+ lock_word_t m_in_use;
+};
+
+/** For storing the allocated blocks */
+typedef std::vector<Block> Blocks;
+
+/** Block collection */
+static Blocks* block_cache;
+
+/** Number of blocks to allocate for sync read/writes */
+static const size_t MAX_BLOCKS = 128;
+
+/** Block buffer size */
+#define BUFFER_BLOCK_SIZE ((ulint)(UNIV_PAGE_SIZE * 1.3))
+
/* This specifies the file permissions InnoDB uses when it creates files in
Unix; the value of os_innodb_umask is initialized in ha_innodb.cc to
my_umask */
@@ -259,7 +283,8 @@ struct Slot {
to the caller of os_aio_simulated_handle */
bool io_already_done;
- ulint file_block_size;/*!< file block size */
+ /*!< file block size */
+ ulint file_block_size;
/** The file node for which the IO is requested. */
fil_node_t* m1;
@@ -307,6 +332,9 @@ struct Slot {
/** Length of the block before it was compressed */
uint32 original_len;
+ /** Buffer block for compressed pages or encrypted pages */
+ Block* buf_block;
+
/** Unaligned buffer for compressed pages */
byte* compressed_ptr;
@@ -360,7 +388,7 @@ public:
os_offset_t offset,
ulint len,
ulint* write_size)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** @return number of reserved slots */
ulint pending_io_count() const;
@@ -369,7 +397,7 @@ public:
@param[in] index Index of the slot in the array
@return pointer to slot */
const Slot* at(ulint i) const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_a(i < m_slots.size());
@@ -378,7 +406,7 @@ public:
/** Non const version */
Slot* at(ulint i)
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_a(i < m_slots.size());
@@ -399,14 +427,14 @@ public:
/** @return the number of slots per segment */
ulint slots_per_segment() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_slots.size() / m_n_segments);
}
/** @return accessor for n_segments */
ulint get_n_segments() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(m_n_segments);
}
@@ -414,7 +442,7 @@ public:
#ifdef UNIV_DEBUG
/** @return true if the thread owns the mutex */
bool is_mutex_owned() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(mutex_own(&m_mutex));
}
@@ -441,13 +469,13 @@ public:
@param[in,out] slot an already reserved slot
@return true on success. */
bool linux_dispatch(Slot* slot)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Accessor for an AIO event
@param[in] index Index into the array
@return the event at the index */
io_event* io_events(ulint index)
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_a(index < m_events.size());
@@ -458,7 +486,7 @@ public:
@param[in] segment Segment for which to get the context
@return the AIO context for the segment */
io_context* io_ctx(ulint segment)
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(segment < get_n_segments());
@@ -470,7 +498,7 @@ public:
@param[out] io_ctx io_ctx to initialize.
@return true on success. */
static bool linux_create_io_ctx(ulint max_events, io_context_t* io_ctx)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Checks if the system supports native linux aio. On some kernel
versions where native aio is supported it won't work on tmpfs. In such
@@ -478,7 +506,7 @@ public:
and native aio.
@return true if supported, false otherwise. */
static bool is_linux_native_aio_supported()
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* LINUX_NATIVE_AIO */
#ifdef WIN_ASYNC_IO
@@ -520,7 +548,7 @@ public:
/** The non asynchronous IO array.
@return the synchronous AIO array instance. */
static AIO* sync_array()
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(s_sync);
}
@@ -530,7 +558,7 @@ public:
@param[in] segment The local segment.
@return the handles for the segment. */
HANDLE* handles(ulint segment)
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(segment < m_handles->size() / slots_per_segment());
@@ -539,7 +567,7 @@ public:
/** @return true if no slots are reserved */
bool is_empty() const
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_ad(is_mutex_owned());
return(m_n_reserved == 0);
@@ -555,7 +583,7 @@ public:
latch_id_t id,
ulint n_slots,
ulint segments)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Initializes the asynchronous io system. Creates one array each
for ibuf and log I/O. Also creates one array each for read and write
@@ -574,7 +602,7 @@ public:
ulint n_readers,
ulint n_writers,
ulint n_slots_sync)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Free the AIO arrays */
static void shutdown();
@@ -591,7 +619,7 @@ public:
static ulint get_array_and_local_segment(
AIO** array,
ulint segment)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Select the IO slot array
@param[in] type Type of IO, READ or WRITE
@@ -602,7 +630,7 @@ public:
IORequest& type,
bool read_only,
ulint mode)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Calculates segment number for a slot.
@param[in] array AIO wait array
@@ -612,7 +640,7 @@ public:
static ulint get_segment_no_from_slot(
const AIO* array,
const Slot* slot)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Wakes up a simulated AIO I/O-handler thread if it has something
to do.
@@ -624,7 +652,7 @@ public:
@param[in] aio The AIO instance to check
@return true if the AIO instance is for reading. */
static bool is_read(const AIO* aio)
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
return(s_reads == aio);
}
@@ -648,7 +676,7 @@ private:
/** Initialise the slots
@return DB_SUCCESS or error code */
dberr_t init_slots()
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
/** Wakes up a simulated AIO I/O-handler thread if it has something
to do for a local segment in the AIO array.
@@ -671,7 +699,7 @@ private:
/** Initialise the Linux native AIO data structures
@return DB_SUCCESS or error code */
dberr_t init_linux_native_aio()
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
#endif /* LINUX_NATIVE_AIO */
private:
@@ -898,6 +926,77 @@ os_aio_windows_handler(
IORequest* type);
#endif /* WIN_ASYNC_IO */
+#ifdef MYSQL_COMPRESSION_ENCRYPTION
+/** Allocate a page for sync IO
+@return pointer to page */
+static
+Block*
+os_alloc_block()
+{
+ size_t pos;
+ Blocks& blocks = *block_cache;
+ size_t i = static_cast<size_t>(my_timer_cycles());
+ const size_t size = blocks.size();
+ ulint retry = 0;
+ Block* block;
+
+ DBUG_EXECUTE_IF("os_block_cache_busy", retry = MAX_BLOCKS * 3;);
+
+ for (;;) {
+
+ /* After go through the block cache for 3 times,
+ allocate a new temporary block. */
+ if (retry == MAX_BLOCKS * 3) {
+ byte* ptr;
+
+ ptr = static_cast<byte*>(
+ ut_malloc_nokey(sizeof(*block)
+ + BUFFER_BLOCK_SIZE));
+
+ block = new (ptr) Block();
+ block->m_ptr = static_cast<byte*>(
+ ptr + sizeof(*block));
+ block->m_in_use = 1;
+
+ break;
+ }
+
+ pos = i++ % size;
+
+ if (TAS(&blocks[pos].m_in_use, 1) == 0) {
+ block = &blocks[pos];
+ break;
+ }
+
+ os_thread_yield();
+
+ ++retry;
+ }
+
+ ut_a(block->m_in_use != 0);
+
+ return(block);
+}
+
+/** Free a page after sync IO
+@param[in,own] block The block to free/release */
+static
+void
+os_free_block(Block* block)
+{
+ ut_ad(block->m_in_use == 1);
+
+ TAS(&block->m_in_use, 0);
+
+ /* When this block is not in the block cache, and it's
+ a temporary block, we need to free it directly. */
+ if (std::less<Block*>()(block, &block_cache->front())
+ || std::greater<Block*>()(block, &block_cache->back())) {
+ ut_free(block);
+ }
+}
+#endif /* MYSQL_COMPRESSION_ENCRYPTION */
+
/** Generic AIO Handler methods. Currently handles IO post processing. */
class AIOHandler {
public:
@@ -920,6 +1019,18 @@ public:
}
private:
+ /** Check whether the page was encrypted.
+ @param[in] slot The slot that contains the IO request
+ @return true if it was an encyrpted page */
+ static bool is_encrypted_page(const Slot* slot)
+ {
+#ifdef MYSQL_ENCRYPTION
+ return(Encryption::is_encrypted_page(slot->buf));
+#else
+ return (false);
+#endif
+ }
+
/** Check whether the page was compressed.
@param[in] slot The slot that contains the IO request
@return true if it was a compressed page */
@@ -994,14 +1105,6 @@ public:
m_offset(offset)
{
ut_ad(m_n > 0);
-
- /* If off_t is > 4 bytes in size, then we assume we can pass a
- 64-bit address */
- off_t offs = static_cast<off_t>(m_offset);
-
- if (sizeof(off_t) <= 4 && m_offset != (os_offset_t) offs) {
- ib::error() << "file write at offset > 4 GB.";
- }
}
/** Destructor */
@@ -1092,7 +1195,7 @@ os_file_original_page_size(const byte* buf)
dberr_t
AIOHandler::check_read(Slot* slot, ulint n_bytes)
{
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
ut_ad(slot->type.is_read());
ut_ad(slot->original_len > slot->len);
@@ -1119,10 +1222,29 @@ AIOHandler::check_read(Slot* slot, ulint n_bytes)
err = DB_FAIL;
}
+ } else if (is_encrypted_page(slot)) {
+ ut_a(slot->offset > 0);
+
+ slot->len = slot->original_len;
+#ifdef _WIN32
+ slot->n_bytes = static_cast<DWORD>(n_bytes);
+#else
+ slot->n_bytes = static_cast<ulint>(n_bytes);
+#endif /* _WIN32 */
+
+ err = io_complete(slot);
+ ut_a(err == DB_SUCCESS);
+
} else {
err = DB_FAIL;
}
+#ifdef MYSQL_COMPRESSION_ENCRYPTION
+ if (slot->buf_block != NULL) {
+ os_free_block(slot->buf_block);
+ slot->buf_block = NULL;
+ }
+#endif
return(err);
}
@@ -1131,7 +1253,7 @@ AIOHandler::check_read(Slot* slot, ulint n_bytes)
dberr_t
AIOHandler::post_io_processing(Slot* slot)
{
- dberr_t err;
+ dberr_t err=DB_SUCCESS;
ut_ad(slot->is_reserved);
@@ -1145,7 +1267,10 @@ AIOHandler::post_io_processing(Slot* slot)
&& slot->type.is_compressed()
&& slot->len == static_cast<ulint>(slot->n_bytes))) {
- if (!slot->type.is_log() && is_compressed_page(slot)) {
+#ifdef MYSQL_COMPRESSION
+ if (!slot->type.is_log()
+ && (is_compressed_page(slot)
+ || is_encrypted_page(slot))) {
ut_a(slot->offset > 0);
@@ -1170,6 +1295,11 @@ AIOHandler::post_io_processing(Slot* slot)
err = DB_SUCCESS;
}
+ if (slot->buf_block != NULL) {
+ os_free_block(slot->buf_block);
+ slot->buf_block = NULL;
+ }
+#endif /* MYSQL_COMPRESSION */
} else if ((ulint) slot->n_bytes == (ulint) slot->len) {
/* It *must* be a partial read. */
@@ -1220,6 +1350,7 @@ AIO::pending_io_count() const
return(reserved);
}
+#ifdef MYSQL_COMPRESSION
/** Compress a data page
#param[in] block_size File system block size
@param[in] src Source contents to compress
@@ -1241,7 +1372,7 @@ os_file_compress_page(
ulint compression_level = page_zip_level;
ulint page_type = mach_read_from_2(src + FIL_PAGE_TYPE);
- /* Must be divisible by the file system block size. */
+ /* The page size must be a multiple of the OS punch hole size. */
ut_ad(!(src_len % block_size));
/* Shouldn't compress an already compressed page. */
@@ -1255,7 +1386,6 @@ os_file_compress_page(
if (page_type == FIL_PAGE_RTREE
|| block_size == ULINT_UNDEFINED
|| compression.m_type == Compression::NONE
- || block_size >= src_len
|| src_len < block_size * 2) {
*dst_len = src_len;
@@ -1367,6 +1497,7 @@ os_file_compress_page(
return(dst);
}
+#endif /* MYSQL_COMPRESSION */
#ifdef UNIV_DEBUG
# ifndef UNIV_HOTBACKUP
@@ -1547,12 +1678,17 @@ AIO::release_with_mutex(Slot* slot)
}
/** Creates a temporary file. This function is like tmpfile(3), but
-@return temporary file handle, or NULL on error */
+the temporary file is created in the given parameter path. If the path
+is NULL then it will create the file in the MySQL server configuration
+parameter (--tmpdir).
+@param[in] path location for creating temporary file
+@@return temporary file handle, or NULL on error */
FILE*
-os_file_create_tmpfile()
+os_file_create_tmpfile(
+ const char* path)
{
FILE* file = NULL;
- int fd = innobase_mysql_tmpfile();
+ int fd = innobase_mysql_tmpfile(path);
if (fd >= 0) {
file = fdopen(fd, "w+b");
@@ -1613,6 +1749,7 @@ os_file_io_complete(
ulint offset,
ulint len)
{
+#ifdef MYSQL_ENCRYPTION_COMPRESSION
/* We never compress/decompress the first page */
ut_a(offset > 0);
ut_ad(type.validate());
@@ -1622,11 +1759,19 @@ os_file_io_complete(
return(DB_SUCCESS);
} else if (type.is_read()) {
+ dberr_t ret = DB_SUCCESS;
+ Encryption encryption(type.encryption_algorithm());
ut_ad(!type.is_log());
- return(os_file_decompress_page(
- type.is_dblwr_recover(), buf, scratch, len));
+ ret = encryption.decrypt(type, buf, src_len, scratch, len);
+ if (ret == DB_SUCCESS) {
+ return(os_file_decompress_page(
+ type.is_dblwr_recover(),
+ buf, scratch, len));
+ } else {
+ return(ret);
+ }
} else if (type.punch_hole()) {
@@ -1660,6 +1805,7 @@ os_file_io_complete(
}
ut_ad(!type.is_log());
+#endif /* MYSQL_ENCRYPTION_COMPRESSION */
return(DB_SUCCESS);
}
@@ -1961,6 +2107,7 @@ os_file_create_subdirs_if_needed(
return(success ? DB_SUCCESS : DB_ERROR);
}
+#ifdef MYSQL_COMPRESSION
/** Allocate the buffer for IO on a transparently compressed table.
@param[in] type IO flags
@param[out] buf buffer to read or write
@@ -1969,7 +2116,7 @@ os_file_create_subdirs_if_needed(
@return pointer to allocated page, compressed data is written to the offset
that is aligned on UNIV_SECTOR_SIZE of Block.m_ptr */
static
-byte*
+Block*
os_file_compress_page(
IORequest& type,
void*& buf,
@@ -1981,13 +2128,13 @@ os_file_compress_page(
ulint n_alloc = *n * 2;
- ut_a(n_alloc < UNIV_PAGE_SIZE_MAX * 2);
+ ut_a(n_alloc <= UNIV_PAGE_SIZE_MAX * 2);
#ifdef HAVE_LZ4
ut_a(type.compression_algorithm().m_type != Compression::LZ4
|| static_cast<ulint>(LZ4_COMPRESSBOUND(*n)) < n_alloc);
#endif
- byte* ptr = reinterpret_cast<byte*>(ut_malloc_nokey(n_alloc));
+ Block* ptr = reinterpret_cast<Block*>(ut_malloc_nokey(n_alloc));
if (ptr == NULL) {
return(NULL);
@@ -2009,7 +2156,7 @@ os_file_compress_page(
byte* compressed_page;
compressed_page = static_cast<byte*>(
- ut_align(ptr, UNIV_SECTOR_SIZE));
+ ut_align(block->m_ptr, UNIV_SECTOR_SIZE));
byte* buf_ptr;
@@ -2037,8 +2184,54 @@ os_file_compress_page(
}
}
- return(ptr);
+ return(block);
}
+#endif /* MYSQL_COMPRESSION */
+
+#ifdef MYSQL_ENCRYPTION
+/** Encrypt a page content when write it to disk.
+@param[in] type IO flags
+@param[out] buf buffer to read or write
+@param[in,out] n number of bytes to read/write, starting from
+ offset
+@return pointer to the encrypted page */
+static
+Block*
+os_file_encrypt_page(
+ const IORequest& type,
+ void*& buf,
+ ulint* n)
+{
+
+ byte* encrypted_page;
+ ulint encrypted_len = *n;
+ byte* buf_ptr;
+ Encryption encryption(type.encryption_algorithm());
+
+ ut_ad(!type.is_log());
+ ut_ad(type.is_write());
+ ut_ad(type.is_encrypted());
+
+ Block* block = os_alloc_block();
+
+ encrypted_page = static_cast<byte*>(
+ ut_align(block->m_ptr, UNIV_SECTOR_SIZE));
+
+ buf_ptr = encryption.encrypt(type,
+ reinterpret_cast<byte*>(buf), *n,
+ encrypted_page, &encrypted_len);
+
+ bool encrypted = buf_ptr != buf;
+
+ if (encrypted) {
+
+ buf = buf_ptr;
+ *n = encrypted_len;
+ }
+
+ return(block);
+}
+#endif /* MYSQL_ENCRYPTION */
#ifndef _WIN32
@@ -2272,7 +2465,7 @@ LinuxAIOHandler::check_state(Slot* slot)
ut_ad(slot->io_already_done);
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
if (slot->ret == 0) {
@@ -2469,7 +2662,7 @@ LinuxAIOHandler::collect()
dberr_t
LinuxAIOHandler::poll(fil_node_t** m1, void** m2, IORequest* request)
{
- dberr_t err;
+ dberr_t err = DB_SUCCESS;
Slot* slot;
/* Loop until we have found a completed request. */
@@ -2722,7 +2915,7 @@ AIO::is_linux_native_aio_supported()
} else if (!srv_read_only_mode) {
/* Now check if tmpdir supports native aio ops. */
- fd = innobase_mysql_tmpfile();
+ fd = innobase_mysql_tmpfile(NULL);
if (fd < 0) {
ib::warn()
@@ -2733,7 +2926,7 @@ AIO::is_linux_native_aio_supported()
}
} else {
- os_normalize_path_for_win(srv_log_group_home_dir);
+ os_normalize_path(srv_log_group_home_dir);
ulint dirnamelen = strlen(srv_log_group_home_dir);
@@ -3522,11 +3715,11 @@ os_file_create_func(
} while (retry);
/* We disable OS caching (O_DIRECT) only on data files */
- if (!srv_read_only_mode
- && *success
- && type != OS_LOG_FILE
- && (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT
- || srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC)) {
+ if (!read_only
+ && *success
+ && (type != OS_LOG_FILE && type != OS_DATA_TEMP_FILE)
+ && (srv_unix_file_flush_method == SRV_UNIX_O_DIRECT
+ || srv_unix_file_flush_method == SRV_UNIX_O_DIRECT_NO_FSYNC)) {
os_file_set_nocache(file, name, mode_str);
}
@@ -5300,6 +5493,7 @@ AIO::simulated_put_read_threads_to_sleep()
#endif /* !_WIN32*/
+#ifdef MYSQL_COMPRESSION
/** Validate the type, offset and number of bytes to read *
@param[in] type IO flags
@param[in] offset Offset from start of the file
@@ -5321,6 +5515,7 @@ os_file_check_args(const IORequest& type, os_offset_t offset, ulint n)
ib::error() << "file write at offset > 4 GB.";
}
}
+#endif /* MYSQL_COMPRESSION */
/** Does a syncronous read or write depending upon the type specified
In case of partial reads/writes the function tries
@@ -5332,7 +5527,7 @@ NUM_RETRIES_ON_PARTIAL_IO times to read/write the complete data.
@param[in] n number of bytes to read, starting from offset
@param[out] err DB_SUCCESS or error code
@return number of bytes read/written, -1 if error */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
ssize_t
os_file_io(
const IORequest&in_type,
@@ -5342,26 +5537,45 @@ os_file_io(
os_offset_t offset,
dberr_t* err)
{
- byte* ptr;
ulint original_n = n;
IORequest type = in_type;
- byte* compressed_page;
+ byte* compressed_page=NULL;
ssize_t bytes_returned = 0;
+#ifdef MYSQL_COMPRESSION
+ Block* block=NULL;
if (type.is_compressed()) {
/* We don't compress the first page of any file. */
ut_ad(offset > 0);
- ptr = os_file_compress_page(type, buf, &n);
+ block = os_file_compress_page(type, buf, &n);
compressed_page = static_cast<byte*>(
- ut_align(ptr, UNIV_SECTOR_SIZE));
+ ut_align(block->m_ptr, UNIV_SECTOR_SIZE));
} else {
- ptr = NULL;
+ block = NULL;
compressed_page = NULL;
}
+#endif /* MYSQL_COMPRESSION */
+
+#ifdef MYSQL_ENCRYPTION
+ /* We do encryption after compression, since if we do encryption
+ before compression, the encrypted data will cause compression fail
+ or low compression rate. */
+ if (type.is_encrypted() && type.is_write()) {
+ /* We don't encrypt the first page of any file. */
+ Block* compressed_block = block;
+ ut_ad(offset > 0);
+
+ block = os_file_encrypt_page(type, buf, &n);
+
+ if (compressed_block != NULL) {
+ os_free_block(compressed_block);
+ }
+ }
+#endif /* MYSQL_ENCRYPTION */
SyncFileIO sync_file_io(file, buf, n, offset);
@@ -5387,14 +5601,15 @@ os_file_io(
compressed_page, original_n,
static_cast<ulint>(offset), n);
- if (ptr != NULL) {
- ut_free(ptr);
- }
-
} else {
*err = DB_SUCCESS;
}
+#ifdef MYSQL_COMPRESSION
+ if (block != NULL) {
+ os_free_block(block);
+ }
+#endif
return(original_n);
}
@@ -5422,9 +5637,11 @@ os_file_io(
sync_file_io.advance(n_bytes);
}
- if (ptr != NULL) {
- ut_free(ptr);
+#ifdef MYSQL_COMPRESSION
+ if (block != NULL) {
+ os_free_block(block);
}
+#endif
*err = DB_IO_ERROR;
@@ -5446,7 +5663,7 @@ os_file_io(
@param[in] offset file offset from the start where to read
@param[out] err DB_SUCCESS or error code
@return number of bytes written, -1 if error */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
ssize_t
os_file_pwrite(
IORequest& type,
@@ -5478,7 +5695,7 @@ os_file_pwrite(
@param[in] offset file offset from the start where to read
@param[in] n number of bytes to read, starting from offset
@return DB_SUCCESS if request was successful, false if fail */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
os_file_write_page(
IORequest& type,
@@ -5490,8 +5707,9 @@ os_file_write_page(
{
dberr_t err;
- os_file_check_args(type, offset, n);
-
+ ut_ad(type.validate());
+ ut_ad(n > 0);
+
ssize_t n_bytes = os_file_pwrite(type, file, buf, n, offset, &err);
if ((ulint) n_bytes != n && !os_has_said_disk_full) {
@@ -5530,7 +5748,7 @@ os_file_write_page(
@param[in] n number of bytes to read, starting from offset
@param[out] err DB_SUCCESS or error code
@return number of bytes read, -1 if error */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
ssize_t
os_file_pread(
IORequest& type,
@@ -5563,7 +5781,7 @@ os_file_pread(
@param[out] o number of bytes actually read
@param[in] exit_on_err if true then exit on error
@return DB_SUCCESS or error code */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
os_file_read_page(
IORequest& type,
@@ -5578,7 +5796,8 @@ os_file_read_page(
os_bytes_read_since_printout += n;
- os_file_check_args(type, offset, n);
+ ut_ad(type.validate());
+ ut_ad(n > 0);
for (;;) {
ssize_t n_bytes;
@@ -5595,6 +5814,7 @@ os_file_read_page(
} else if ((ulint) n_bytes == n) {
+#ifdef MYSQL_COMPRESSION
/** The read will succeed but decompress can fail
for various reasons. */
@@ -5607,11 +5827,14 @@ os_file_read_page(
} else {
return(err);
}
+#else
+ return(DB_SUCCESS);
+#endif /* MYSQL_COMPRESSION */
}
- ib::error()
- << "Tried to read " << n << " bytes at offset "
- << offset << " was only able to read" << n_bytes;
+ ib::error() << "Tried to read " << n
+ << " bytes at offset " << offset
+ << ", but was only able to read " << n_bytes;
if (exit_on_err) {
@@ -5664,7 +5887,7 @@ and the error type, if should_exit is true then on_error_silent is ignored.
@param[in] on_error_silent if true then don't print any message to the log
iff it is an unknown non-fatal error
@return true if we should retry the operation */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
os_file_handle_error_cond_exit(
const char* name,
@@ -5785,9 +6008,9 @@ os_file_handle_error_no_exit(
message */
void
os_file_set_nocache(
- os_file_t fd __attribute__((unused)),
- const char* file_name __attribute__((unused)),
- const char* operation_name __attribute__((unused)))
+ os_file_t fd MY_ATTRIBUTE((unused)),
+ const char* file_name MY_ATTRIBUTE((unused)),
+ const char* operation_name MY_ATTRIBUTE((unused)))
{
/* some versions of Solaris may not have DIRECTIO_ON */
#if defined(UNIV_SOLARIS) && defined(DIRECTIO_ON)
@@ -6064,6 +6287,13 @@ os_file_punch_hole(
os_offset_t off,
os_offset_t len)
{
+ /* In this debugging mode, we act as if punch hole is supported,
+ and then skip any calls to actually punch a hole here.
+ In this way, Transparent Page Compression is still being tested. */
+ DBUG_EXECUTE_IF("ignore_punch_hole",
+ return(DB_SUCCESS);
+ );
+
#ifdef _WIN32
return(os_file_punch_hole_win32(fh, off, len));
#else
@@ -6085,6 +6315,13 @@ Note: On Windows we use the name and on Unices we use the file handle.
bool
os_is_sparse_file_supported(const char* path, os_file_t fh)
{
+ /* In this debugging mode, we act as if punch hole is supported,
+ then we skip any calls to actually punch a hole. In this way,
+ Transparent Page Compression is still being tested. */
+ DBUG_EXECUTE_IF("ignore_punch_hole",
+ return(true);
+ );
+
#ifdef _WIN32
return(os_is_sparse_file_supported_win32(path));
#else
@@ -6575,6 +6812,26 @@ os_aio_init(
}
#endif /* _WIN32 */
+ ut_a(block_cache == NULL);
+
+ block_cache = UT_NEW_NOKEY(Blocks(MAX_BLOCKS));
+
+ for (Blocks::iterator it = block_cache->begin();
+ it != block_cache->end();
+ ++it) {
+
+ ut_a(it->m_in_use == 0);
+ ut_a(it->m_ptr == NULL);
+
+ /* Allocate double of max page size memory, since
+ compress could generate more bytes than orgininal
+ data. */
+ it->m_ptr = static_cast<byte*>(
+ ut_malloc_nokey(BUFFER_BLOCK_SIZE));
+
+ ut_a(it->m_ptr != NULL);
+ }
+
return(AIO::start(limit, n_readers, n_writers, n_slots_sync));
}
@@ -6591,6 +6848,18 @@ os_aio_free()
ut_free(os_aio_segment_wait_events);
os_aio_segment_wait_events = 0;
os_aio_n_segments = 0;
+
+ for (Blocks::iterator it = block_cache->begin();
+ it != block_cache->end();
+ ++it) {
+
+ ut_a(it->m_in_use == 0);
+ ut_free(it->m_ptr);
+ }
+
+ UT_DELETE(block_cache);
+
+ block_cache = NULL;
}
/** Wakes up all async i/o threads so that they know to exit themselves in
@@ -6796,70 +7065,78 @@ AIO::reserve_slot(
slot->is_log = type.is_log();
slot->original_len = static_cast<uint32>(len);
slot->io_already_done = false;
+ slot->buf_block = NULL;
slot->buf = static_cast<byte*>(buf);
+#ifdef MYSQL_COMPRESSION
if (srv_use_native_aio
&& offset > 0
&& type.is_write()
&& type.is_compressed()) {
+ ulint compressed_len = len;
ut_ad(!type.is_log());
release();
- ulint compressed_len = len;
-
- ulint old_compressed_len;
-
- old_compressed_len = mach_read_from_2(
- slot->buf + FIL_PAGE_COMPRESS_SIZE_V1);
+ void* src_buf = slot->buf;
- if (old_compressed_len > 0) {
- old_compressed_len = ut_calc_align(
- old_compressed_len + FIL_PAGE_DATA,
- slot->type.block_size());
- }
-
- byte* ptr;
-
- ptr = os_file_compress_page(
- slot->type.compression_algorithm(),
- slot->type.block_size(),
- slot->buf,
- slot->len,
- slot->compressed_page,
+ slot->buf_block = os_file_compress_page(
+ type,
+ src_buf,
&compressed_len);
- if (ptr != buf) {
- /* Set new compressed size to uncompressed page. */
- memcpy(slot->buf + FIL_PAGE_COMPRESS_SIZE_V1,
- slot->compressed_page
- + FIL_PAGE_COMPRESS_SIZE_V1, 2);
+ slot->buf = static_cast<byte*>(src_buf);
+ slot->ptr = slot->buf;
#ifdef _WIN32
- slot->len = static_cast<DWORD>(compressed_len);
+ slot->len = static_cast<DWORD>(compressed_len);
#else
- slot->len = static_cast<ulint>(compressed_len);
+ slot->len = static_cast<ulint>(compressed_len);
#endif /* _WIN32 */
- slot->buf = slot->compressed_page;
- slot->ptr = slot->buf;
+ slot->skip_punch_hole = type.punch_hole();
- if (old_compressed_len > 0
- && compressed_len >= old_compressed_len) {
+ acquire();
+ }
+#endif /* MYSQL_COMPRESSION */
- ut_ad(old_compressed_len <= UNIV_PAGE_SIZE);
+#ifdef MYSQL_ENCRYPTION
+ /* We do encryption after compression, since if we do encryption
+ before compression, the encrypted data will cause compression fail
+ or low compression rate. */
+ if (srv_use_native_aio
+ && offset > 0
+ && type.is_write()
+ && type.is_encrypted()) {
+ ulint encrypted_len = slot->len;
+ Block* encrypted_block;
- slot->skip_punch_hole = true;
+ ut_ad(!type.is_log());
- } else {
- slot->skip_punch_hole = false;
- }
+ release();
- } else {
- slot->skip_punch_hole = false;
+ void* src_buf = slot->buf;
+ encrypted_block = os_file_encrypt_page(
+ type,
+ src_buf,
+ &encrypted_len);
+
+ if (slot->buf_block != NULL) {
+ os_free_block(slot->buf_block);
}
+ slot->buf_block = encrypted_block;
+ slot->buf = static_cast<byte*>(src_buf);
+ slot->ptr = slot->buf;
+
+#ifdef _WIN32
+ slot->len = static_cast<DWORD>(encrypted_len);
+#else
+ slot->len = static_cast<ulint>(encrypted_len);
+#endif /* _WIN32 */
+
acquire();
- }
+ }
+#endif /* MYSQL_ENCRYPTION */
#ifdef WIN_ASYNC_IO
{
@@ -7501,7 +7778,7 @@ public:
all data, and perform the I/O
@return the length of the buffer */
ulint allocate_buffer()
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ulint len;
Slot* slot = first_slot();
@@ -7591,7 +7868,7 @@ public:
/** @return the first slot in the consecutive array */
Slot* first_slot()
- __attribute__((warn_unused_result))
+ MY_ATTRIBUTE((warn_unused_result))
{
ut_a(m_n_elems > 0);
@@ -7605,7 +7882,7 @@ public:
ulint check_pending(
ulint global_segment,
os_event_t event)
- __attribute__((warn_unused_result));
+ MY_ATTRIBUTE((warn_unused_result));
private:
/** Do the file read
@@ -8095,7 +8372,7 @@ os_aio_print(FILE* file)
for (ulint i = 0; i < srv_n_file_io_threads; ++i) {
fprintf(file, "I/O thread %lu state: %s (%s)",
- (ulong) i,
+ (ulint) i,
srv_io_thread_op_info[i],
srv_io_thread_function[i]);
@@ -8119,17 +8396,17 @@ os_aio_print(FILE* file)
fprintf(file,
"Pending flushes (fsync) log: %lu; buffer pool: %lu\n"
"%lu OS file reads, %lu OS file writes, %lu OS fsyncs\n",
- (ulong) fil_n_pending_log_flushes,
- (ulong) fil_n_pending_tablespace_flushes,
- (ulong) os_n_file_reads,
- (ulong) os_n_file_writes,
- (ulong) os_n_fsyncs);
+ (ulint) fil_n_pending_log_flushes,
+ (ulint) fil_n_pending_tablespace_flushes,
+ (ulint) os_n_file_reads,
+ (ulint) os_n_file_writes,
+ (ulint) os_n_fsyncs);
if (os_n_pending_writes != 0 || os_n_pending_reads != 0) {
fprintf(file,
"%lu pending preads, %lu pending pwrites\n",
(ulint) os_n_pending_reads,
- (ulong) os_n_pending_writes);
+ (ulint) os_n_pending_writes);
}
if (os_n_file_reads == os_n_file_reads_old) {
@@ -8144,7 +8421,7 @@ os_aio_print(FILE* file)
" %.2f writes/s, %.2f fsyncs/s\n",
(os_n_file_reads - os_n_file_reads_old)
/ time_elapsed,
- (ulong) avg_bytes_read,
+ (ulint) avg_bytes_read,
(os_n_file_writes - os_n_file_writes_old)
/ time_elapsed,
(os_n_fsyncs - os_n_fsyncs_old)
@@ -8276,9 +8553,38 @@ os_file_set_umask(ulint umask)
#endif
#include <zlib.h>
+#ifndef UNIV_INNOCHECKSUM
+#include <my_aes.h>
+#include <my_rnd.h>
+#include <mysqld.h>
+#include <mysql/service_mysql_keyring.h>
+#endif
+typedef byte Block;
+
+#ifdef MYSQL_COMPRESSION
+/** Allocate a page for sync IO
+@return pointer to page */
+static
+Block*
+os_alloc_block()
+{
+ return(reinterpret_cast<byte*>(malloc(UNIV_PAGE_SIZE_MAX * 2)));
+}
+
+/** Free a page after sync IO
+@param[in,own] block The block to free/release */
+static
+void
+os_free_block(Block* block)
+{
+ ut_free(block);
+}
+#endif
#endif /* !UNIV_INNOCHECKSUM */
+#ifdef MYSQL_COMPRESSION
+
/**
@param[in] type The compression type
@return the string representation */
@@ -8388,32 +8694,24 @@ Compression::deserialize(
return(DB_CORRUPTION);
}
- // FIXME: We should use TLS for this and reduce the malloc/free
- bool allocated;
+ Block* block;
/* The caller doesn't know what to expect */
if (dst == NULL) {
- /* Add a safety margin of an additional 50% */
- ulint n_bytes = header.m_original_size
- + (header.m_original_size / 2);
+ block = os_alloc_block();
-#ifndef UNIV_INNOCHECKSUM
- dst = reinterpret_cast<byte*>(ut_malloc_nokey(n_bytes));
+#ifdef UNIV_INNOCHECKSUM
+ dst = block;
#else
- dst = reinterpret_cast<byte*>(malloc(n_bytes));
-#endif /* !UNIV_INNOCHECKSUM */
-
- if (dst == NULL) {
-
- return(DB_OUT_OF_MEMORY);
- }
+ dst = block->m_ptr;
+#endif /* UNIV_INNOCHECKSUM */
- allocated = true;
} else {
- allocated = false;
+ block = NULL;
}
+ int ret;
Compression compression;
ulint len = header.m_original_size;
@@ -8427,8 +8725,8 @@ Compression::deserialize(
if (uncompress(dst, &zlen, ptr, header.m_compressed_size)
!= Z_OK) {
- if (allocated) {
- ut_free(dst);
+ if (block != NULL) {
+ os_free_block(block);
}
return(DB_IO_DECOMPRESS_FAIL);
@@ -8467,8 +8765,8 @@ Compression::deserialize(
if (ret < 0) {
- if (allocated) {
- ut_free(dst);
+ if (block != NULL) {
+ os_free_block(block);
}
return(DB_IO_DECOMPRESS_FAIL);
@@ -8487,8 +8785,8 @@ Compression::deserialize(
Compression::to_string(compression.m_type));
#endif /* !UNIV_INNOCHECKSUM */
- if (allocated) {
- ut_free(dst);
+ if (block != NULL) {
+ os_free_block(block);
}
return(DB_UNSUPPORTED);
@@ -8503,9 +8801,10 @@ Compression::deserialize(
src + (header.m_original_size + FIL_PAGE_DATA)
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4, 4) == 0);
- if (allocated) {
- ut_free(dst);
+ if (block != NULL) {
+ os_free_block(block);
}
+
return(DB_SUCCESS);
}
@@ -8526,6 +8825,635 @@ os_file_decompress_page(
{
return(Compression::deserialize(dblwr_recover, src, dst, dst_len));
}
+#endif /* MYSQL_COMPRESSION */
+
+#ifdef MYSQL_ENCRYPTION
+
+/**
+@param[in] type The encryption type
+@return the string representation */
+const char*
+Encryption::to_string(Type type)
+{
+ switch(type) {
+ case NONE:
+ return("N");
+ case AES:
+ return("Y");
+ }
+
+ ut_ad(0);
+
+ return("<UNKNOWN>");
+}
+
+/** Generate random encryption value for key and iv.
+@param[in,out] value Encryption value */
+void Encryption::random_value(byte* value)
+{
+ ut_ad(value != NULL);
+
+ my_rand_buffer(value, ENCRYPTION_KEY_LEN);
+}
+
+/** Create new master key for key rotation.
+@param[in,out] master_key master key */
+void
+Encryption::create_master_key(byte** master_key)
+{
+#ifndef UNIV_INNOCHECKSUM
+ char* key_type = NULL;
+ size_t key_len;
+ char key_name[ENCRYPTION_MASTER_KEY_NAME_MAX_LEN];
+ int ret;
+
+ /* If uuid does not match with current server uuid,
+ set uuid as current server uuid. */
+ if (strcmp(uuid, server_uuid) != 0) {
+ memcpy(uuid, server_uuid, ENCRYPTION_SERVER_UUID_LEN);
+ }
+ memset(key_name, 0, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN);
+
+ /* Generate new master key */
+ ut_snprintf(key_name, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN,
+ "%s-%s-%lu", ENCRYPTION_MASTER_KEY_PRIFIX,
+ uuid, master_key_id + 1);
+
+ /* We call key ring API to generate master key here. */
+ ret = my_key_generate(key_name, "AES",
+ NULL, ENCRYPTION_KEY_LEN);
+
+ /* We call key ring API to get master key here. */
+ ret = my_key_fetch(key_name, &key_type, NULL,
+ reinterpret_cast<void**>(master_key),
+ &key_len);
+
+ if (ret || *master_key == NULL) {
+ ib::error() << "Encryption can't find master key, please check"
+ " the keyring plugin is loaded.";
+ *master_key = NULL;
+ } else {
+ master_key_id++;
+ }
+
+ if (key_type) {
+ my_free(key_type);
+ }
+#endif
+}
+
+/** Get master key by key id.
+@param[in] master_key_id master key id
+@param[in] srv_uuid uuid of server instance
+@param[in,out] master_key master key */
+void
+Encryption::get_master_key(ulint master_key_id,
+ char* srv_uuid,
+ byte** master_key)
+{
+#ifndef UNIV_INNOCHECKSUM
+ char* key_type = NULL;
+ size_t key_len;
+ char key_name[ENCRYPTION_MASTER_KEY_NAME_MAX_LEN];
+ int ret;
+
+ memset(key_name, 0, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN);
+
+ if (srv_uuid != NULL) {
+ ut_snprintf(key_name, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN,
+ "%s-%s-%lu", ENCRYPTION_MASTER_KEY_PRIFIX,
+ srv_uuid, master_key_id);
+ } else {
+ /* For compitable with 5.7.11, we need to get master key with
+ server id. */
+ memset(key_name, 0, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN);
+ ut_snprintf(key_name, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN,
+ "%s-%lu-%lu", ENCRYPTION_MASTER_KEY_PRIFIX,
+ server_id, master_key_id);
+ }
+
+ /* We call key ring API to get master key here. */
+ ret = my_key_fetch(key_name, &key_type, NULL,
+ reinterpret_cast<void**>(master_key), &key_len);
+
+ if (key_type) {
+ my_free(key_type);
+ }
+
+ if (ret) {
+ *master_key = NULL;
+ ib::error() << "Encryption can't find master key, please check"
+ " the keyring plugin is loaded.";
+ }
+
+#ifdef UNIV_ENCRYPT_DEBUG
+ if (!ret && *master_key) {
+ fprintf(stderr, "Fetched master key:%lu ", master_key_id);
+ ut_print_buf(stderr, *master_key, key_len);
+ fprintf(stderr, "\n");
+ }
+#endif /* DEBUG_TDE */
+
+#endif
+}
+
+/** Current master key id */
+ulint Encryption::master_key_id = 0;
+
+/** Current uuid of server instance */
+char Encryption::uuid[ENCRYPTION_SERVER_UUID_LEN + 1] = {0};
+
+/** Get current master key and master key id
+@param[in,out] master_key_id master key id
+@param[in,out] master_key master key
+@param[in,out] version encryption information version */
+void
+Encryption::get_master_key(ulint* master_key_id,
+ byte** master_key,
+ Encryption::Version* version)
+{
+#ifndef UNIV_INNOCHECKSUM
+ char* key_type = NULL;
+ size_t key_len;
+ char key_name[ENCRYPTION_MASTER_KEY_NAME_MAX_LEN];
+ int ret;
+
+ memset(key_name, 0, ENCRYPTION_KEY_LEN);
+ *version = Encryption::ENCRYPTION_VERSION_2;
+
+ if (Encryption::master_key_id == 0) {
+ /* If m_master_key is 0, means there's no encrypted
+ tablespace, we need to generate the first master key,
+ and store it to key ring. */
+ memset(uuid, 0, ENCRYPTION_SERVER_UUID_LEN + 1);
+ memcpy(uuid, server_uuid, ENCRYPTION_SERVER_UUID_LEN);
+
+ /* Prepare the server uuid. */
+ ut_snprintf(key_name, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN,
+ "%s-%s-1", ENCRYPTION_MASTER_KEY_PRIFIX,
+ uuid);
+
+ /* We call key ring API to generate master key here. */
+ ret = my_key_generate(key_name, "AES",
+ NULL, ENCRYPTION_KEY_LEN);
+
+ /* We call key ring API to get master key here. */
+ ret = my_key_fetch(key_name, &key_type, NULL,
+ reinterpret_cast<void**>(master_key),
+ &key_len);
+
+ if (!ret && *master_key != NULL) {
+ Encryption::master_key_id++;
+ *master_key_id = Encryption::master_key_id;
+ }
+#ifdef UNIV_ENCRYPT_DEBUG
+ if (!ret && *master_key) {
+ fprintf(stderr, "Generated new master key:");
+ ut_print_buf(stderr, *master_key, key_len);
+ fprintf(stderr, "\n");
+ }
+#endif
+ } else {
+ *master_key_id = Encryption::master_key_id;
+
+ ut_snprintf(key_name, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN,
+ "%s-%s-%lu", ENCRYPTION_MASTER_KEY_PRIFIX,
+ uuid, *master_key_id);
+
+ /* We call key ring API to get master key here. */
+ ret = my_key_fetch(key_name, &key_type, NULL,
+ reinterpret_cast<void**>(master_key),
+ &key_len);
+
+ /* For compitable with 5.7.11, we need to try to get master key with
+ server id when get master key with server uuid failure. */
+ if (ret || *master_key == NULL) {
+ if (key_type) {
+ my_free(key_type);
+ }
+
+ memset(key_name, 0,
+ ENCRYPTION_MASTER_KEY_NAME_MAX_LEN);
+ ut_snprintf(key_name, ENCRYPTION_MASTER_KEY_NAME_MAX_LEN,
+ "%s-%lu-%lu", ENCRYPTION_MASTER_KEY_PRIFIX,
+ server_id, *master_key_id);
+
+ ret = my_key_fetch(key_name, &key_type, NULL,
+ reinterpret_cast<void**>(master_key),
+ &key_len);
+ *version = Encryption::ENCRYPTION_VERSION_1;
+ }
+#ifdef UNIV_ENCRYPT_DEBUG
+ if (!ret && *master_key) {
+ fprintf(stderr, "Fetched master key:%lu ",
+ *master_key_id);
+ ut_print_buf(stderr, *master_key, key_len);
+ fprintf(stderr, "\n");
+ }
+#endif
+ }
+
+ if (ret) {
+ *master_key = NULL;
+ ib::error() << "Encryption can't find master key, please check"
+ " the keyring plugin is loaded.";
+ }
+
+ if (key_type) {
+ my_free(key_type);
+ }
+#endif
+}
+
+/** Check if page is encrypted page or not
+@param[in] page page which need to check
+@return true if it is a encrypted page */
+bool
+Encryption::is_encrypted_page(const byte* page)
+{
+ ulint page_type = mach_read_from_2(page + FIL_PAGE_TYPE);
+
+ return(page_type == FIL_PAGE_ENCRYPTED
+ || page_type == FIL_PAGE_COMPRESSED_AND_ENCRYPTED
+ || page_type == FIL_PAGE_ENCRYPTED_RTREE);
+}
+
+/** Encrypt the page data contents. Page type can't be
+FIL_PAGE_ENCRYPTED, FIL_PAGE_COMPRESSED_AND_ENCRYPTED,
+FIL_PAGE_ENCRYPTED_RTREE.
+@param[in] type IORequest
+@param[in,out] src page data which need to encrypt
+@param[in] src_len Size of the source in bytes
+@param[in,out] dst destination area
+@param[in,out] dst_len Size of the destination in bytes
+@return buffer data, dst_len will have the length of the data */
+byte*
+Encryption::encrypt(
+ const IORequest& type,
+ byte* src,
+ ulint src_len,
+ byte* dst,
+ ulint* dst_len)
+{
+ ulint len = 0;
+ ulint page_type = mach_read_from_2(src + FIL_PAGE_TYPE);
+ ulint data_len;
+ ulint main_len;
+ ulint remain_len;
+ byte remain_buf[MY_AES_BLOCK_SIZE * 2];
+
+#ifdef UNIV_ENCRYPT_DEBUG
+ ulint space_id =
+ mach_read_from_4(src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ ulint page_no = mach_read_from_4(src + FIL_PAGE_OFFSET);
+
+ fprintf(stderr, "Encrypting page:%lu.%lu len:%lu\n",
+ space_id, page_no, src_len);
+#endif
+
+ /* Shouldn't encrypte an already encrypted page. */
+ ut_ad(page_type != FIL_PAGE_ENCRYPTED
+ && page_type != FIL_PAGE_COMPRESSED_AND_ENCRYPTED
+ && page_type != FIL_PAGE_ENCRYPTED_RTREE);
+
+ ut_ad(m_type != Encryption::NONE);
+
+ /* This is data size which need to encrypt. */
+ data_len = src_len - FIL_PAGE_DATA;
+ main_len = (data_len / MY_AES_BLOCK_SIZE) * MY_AES_BLOCK_SIZE;
+ remain_len = data_len - main_len;
+
+ /* Only encrypt the data + trailer, leave the header alone */
+
+ switch (m_type) {
+ case Encryption::NONE:
+ ut_error;
+
+ case Encryption::AES: {
+ lint elen;
+
+ ut_ad(m_klen == ENCRYPTION_KEY_LEN);
+
+ elen = my_aes_encrypt(
+ src + FIL_PAGE_DATA,
+ static_cast<uint32>(main_len),
+ dst + FIL_PAGE_DATA,
+ reinterpret_cast<unsigned char*>(m_key),
+ static_cast<uint32>(m_klen),
+ my_aes_256_cbc,
+ reinterpret_cast<unsigned char*>(m_iv),
+ false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ ulint page_no =mach_read_from_4(
+ src + FIL_PAGE_OFFSET);
+ ulint space_id = mach_read_from_4(
+ src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ *dst_len = src_len;
+#ifndef UNIV_INNOCHECKSUM
+ ib::warn()
+ << " Can't encrypt data of page,"
+ << " page no:" << page_no
+ << " space id:" << space_id;
+#else
+ fprintf(stderr, " Can't encrypt data of page,"
+ " page no:" ULINTPF
+ " space id:" ULINTPF,
+ page_no, space_id);
+#endif /* !UNIV_INNOCHECKSUM */
+ return(src);
+ }
+
+ len = static_cast<ulint>(elen);
+ ut_ad(len == main_len);
+
+ /* Copy remain bytes and page tailer. */
+ memcpy(dst + FIL_PAGE_DATA + len,
+ src + FIL_PAGE_DATA + len,
+ src_len - FIL_PAGE_DATA - len);
+
+ /* Encrypt the remain bytes. */
+ if (remain_len != 0) {
+ remain_len = MY_AES_BLOCK_SIZE * 2;
+
+ elen = my_aes_encrypt(
+ dst + FIL_PAGE_DATA + data_len - remain_len,
+ static_cast<uint32>(remain_len),
+ remain_buf,
+ reinterpret_cast<unsigned char*>(m_key),
+ static_cast<uint32>(m_klen),
+ my_aes_256_cbc,
+ reinterpret_cast<unsigned char*>(m_iv),
+ false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ ulint page_no =mach_read_from_4(
+ src + FIL_PAGE_OFFSET);
+ ulint space_id = mach_read_from_4(
+ src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+#ifndef UNIV_INNOCHECKSUM
+ ib::warn()
+ << " Can't encrypt data of page,"
+ << " page no:" << page_no
+ << " space id:" << space_id;
+#else
+ fprintf(stderr, " Can't encrypt data of page,"
+ " page no:" ULINTPF
+ " space id:" ULINTPF,
+ page_no, space_id);
+#endif /* !UNIV_INNOCHECKSUM */
+ *dst_len = src_len;
+ return(src);
+ }
+
+ memcpy(dst + FIL_PAGE_DATA + data_len - remain_len,
+ remain_buf, remain_len);
+ }
+
+
+ break;
+ }
+
+ default:
+ ut_error;
+ }
+
+ /* Copy the header as is. */
+ memmove(dst, src, FIL_PAGE_DATA);
+ ut_ad(memcmp(src, dst, FIL_PAGE_DATA) == 0);
+
+ /* Add encryption control information. Required for decrypting. */
+ if (page_type == FIL_PAGE_COMPRESSED) {
+ /* If the page is compressed, we don't need to save the
+ original type, since it is done in compression already. */
+ mach_write_to_2(dst + FIL_PAGE_TYPE,
+ FIL_PAGE_COMPRESSED_AND_ENCRYPTED);
+ ut_ad(memcmp(src+FIL_PAGE_TYPE+2,
+ dst+FIL_PAGE_TYPE+2,
+ FIL_PAGE_DATA-FIL_PAGE_TYPE-2) == 0);
+ } else if (page_type == FIL_PAGE_RTREE) {
+ /* If the page is R-tree page, we need to save original
+ type. */
+ mach_write_to_2(dst + FIL_PAGE_TYPE, FIL_PAGE_ENCRYPTED_RTREE);
+ } else{
+ mach_write_to_2(dst + FIL_PAGE_TYPE, FIL_PAGE_ENCRYPTED);
+ mach_write_to_2(dst + FIL_PAGE_ORIGINAL_TYPE_V1, page_type);
+ }
+
+#ifdef UNIV_ENCRYPT_DEBUG
+#ifndef UNIV_INNOCHECKSUM
+#if 0
+ byte* check_buf = static_cast<byte*>(ut_malloc_nokey(src_len));
+ byte* buf2 = static_cast<byte*>(ut_malloc_nokey(src_len));
+
+ memcpy(check_buf, dst, src_len);
+
+ dberr_t err = decrypt(type, check_buf, src_len, buf2, src_len);
+ if (err != DB_SUCCESS || memcmp(src + FIL_PAGE_DATA,
+ check_buf + FIL_PAGE_DATA,
+ src_len - FIL_PAGE_DATA) != 0) {
+ ut_print_buf(stderr, src, src_len);
+ ut_print_buf(stderr, check_buf, src_len);
+ ut_ad(0);
+ }
+ ut_free(buf2);
+ ut_free(check_buf);
+#endif
+ fprintf(stderr, "Encrypted page:%lu.%lu\n", space_id, page_no);
+#endif
+#endif
+ *dst_len = src_len;
+
+
+ return(dst);
+}
+
+/** Decrypt the page data contents. Page type must be FIL_PAGE_ENCRYPTED,
+if not then the source contents are left unchanged and DB_SUCCESS is returned.
+@param[in] type IORequest
+@param[in,out] src Data read from disk, decrypted data will be
+ copied to this page
+@param[in] src_len source data length
+@param[in,out] dst Scratch area to use for decryption
+@param[in] dst_len Size of the scratch area in bytes
+@return DB_SUCCESS or error code */
+dberr_t
+Encryption::decrypt(
+ const IORequest& type,
+ byte* src,
+ ulint src_len,
+ byte* dst,
+ ulint dst_len)
+{
+ ulint data_len;
+ ulint main_len;
+ ulint remain_len;
+ ulint original_type;
+ ulint page_type;
+ byte remain_buf[MY_AES_BLOCK_SIZE * 2];
+ Block* block;
+
+ /* Do nothing if it's not an encrypted table. */
+ if (!is_encrypted_page(src)) {
+ return(DB_SUCCESS);
+ }
+
+ /* For compressed page, we need to get the compressed size
+ for decryption */
+ page_type = mach_read_from_2(src + FIL_PAGE_TYPE);
+ if (page_type == FIL_PAGE_COMPRESSED_AND_ENCRYPTED) {
+ src_len = static_cast<uint16_t>(
+ mach_read_from_2(src + FIL_PAGE_COMPRESS_SIZE_V1))
+ + FIL_PAGE_DATA;
+#ifndef UNIV_INNOCHECKSUM
+ src_len = ut_calc_align(src_len, type.block_size());
+#endif
+ }
+#ifdef UNIV_ENCRYPT_DEBUG
+ ulint space_id =
+ mach_read_from_4(src + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
+ ulint page_no = mach_read_from_4(src + FIL_PAGE_OFFSET);
+
+ fprintf(stderr, "Decrypting page:%lu.%lu len:%lu\n",
+ space_id, page_no, src_len);
+#endif
+
+ original_type = static_cast<uint16_t>(
+ mach_read_from_2(src + FIL_PAGE_ORIGINAL_TYPE_V1));
+
+ byte* ptr = src + FIL_PAGE_DATA;
+
+ /* The caller doesn't know what to expect */
+ if (dst == NULL) {
+
+ block = os_alloc_block();
+#ifdef UNIV_INNOCHECKSUM
+ dst = block;
+#else
+ dst = block->m_ptr;
+#endif /* UNIV_INNOCHECKSUM */
+
+ } else {
+ block = NULL;
+ }
+
+ data_len = src_len - FIL_PAGE_DATA;
+ main_len = (data_len / MY_AES_BLOCK_SIZE) * MY_AES_BLOCK_SIZE;
+ remain_len = data_len - main_len;
+
+ switch(m_type) {
+ case Encryption::AES: {
+ lint elen;
+
+ /* First decrypt the last 2 blocks data of data, since
+ data is no block aligned. */
+ if (remain_len != 0) {
+ ut_ad(m_klen == ENCRYPTION_KEY_LEN);
+
+ remain_len = MY_AES_BLOCK_SIZE * 2;
+
+ /* Copy the last 2 blocks. */
+ memcpy(remain_buf,
+ ptr + data_len - remain_len,
+ remain_len);
+
+ elen = my_aes_decrypt(
+ remain_buf,
+ static_cast<uint32>(remain_len),
+ dst + data_len - remain_len,
+ reinterpret_cast<unsigned char*>(m_key),
+ static_cast<uint32>(m_klen),
+ my_aes_256_cbc,
+ reinterpret_cast<unsigned char*>(m_iv),
+ false);
+ if (elen == MY_AES_BAD_DATA) {
+ if (block != NULL) {
+ os_free_block(block);
+ }
+
+ return(DB_IO_DECRYPT_FAIL);
+ }
+
+ /* Copy the other data bytes to temp area. */
+ memcpy(dst, ptr, data_len - remain_len);
+ } else {
+ ut_ad(data_len == main_len);
+
+ /* Copy the data bytes to temp area. */
+ memcpy(dst, ptr, data_len);
+ }
+
+ /* Then decrypt the main data */
+ elen = my_aes_decrypt(
+ dst,
+ static_cast<uint32>(main_len),
+ ptr,
+ reinterpret_cast<unsigned char*>(m_key),
+ static_cast<uint32>(m_klen),
+ my_aes_256_cbc,
+ reinterpret_cast<unsigned char*>(m_iv),
+ false);
+ if (elen == MY_AES_BAD_DATA) {
+
+ if (block != NULL) {
+ os_free_block(block);
+ }
+
+ return(DB_IO_DECRYPT_FAIL);
+ }
+
+ ut_ad(static_cast<ulint>(elen) == main_len);
+
+ /* Copy the remain bytes. */
+ memcpy(ptr + main_len, dst + main_len, data_len - main_len);
+
+ break;
+ }
+
+ default:
+#if !defined(UNIV_INNOCHECKSUM)
+ ib::error()
+ << "Encryption algorithm support missing: "
+ << Encryption::to_string(m_type);
+#else
+ fprintf(stderr, "Encryption algorithm support missing: %s\n",
+ Encryption::to_string(m_type));
+#endif /* !UNIV_INNOCHECKSUM */
+
+ if (block != NULL) {
+ os_free_block(block);
+ }
+
+ return(DB_UNSUPPORTED);
+ }
+
+ /* Restore the original page type. If it's a compressed and
+ encrypted page, just reset it as compressed page type, since
+ we will do uncompress later. */
+
+ if (page_type == FIL_PAGE_ENCRYPTED) {
+ mach_write_to_2(src + FIL_PAGE_TYPE, original_type);
+ mach_write_to_2(src + FIL_PAGE_ORIGINAL_TYPE_V1, 0);
+ } else if (page_type == FIL_PAGE_ENCRYPTED_RTREE) {
+ mach_write_to_2(src + FIL_PAGE_TYPE, FIL_PAGE_RTREE);
+ } else {
+ ut_ad(page_type == FIL_PAGE_COMPRESSED_AND_ENCRYPTED);
+ mach_write_to_2(src + FIL_PAGE_TYPE, FIL_PAGE_COMPRESSED);
+ }
+
+ if (block != NULL) {
+ os_free_block(block);
+ }
+
+#ifdef UNIV_ENCRYPT_DEBUG
+ fprintf(stderr, "Decrypted page:%lu.%lu\n", space_id, page_no);
+#endif
+
+ DBUG_EXECUTE_IF("ib_crash_during_decrypt_page", DBUG_SUICIDE(););
+
+ return(DB_SUCCESS);
+}
+#endif /* MYSQL_ENCRYPTION */
/** Normalizes a directory path for the current OS:
On Windows, we convert '/' to '\', else we convert '\' to '/'.
diff --git a/storage/innobase/os/os0sync.cc b/storage/innobase/os/os0sync.cc
deleted file mode 100644
index 03c53848832..00000000000
--- a/storage/innobase/os/os0sync.cc
+++ /dev/null
@@ -1,935 +0,0 @@
-/*****************************************************************************
-
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
-
-This program is free software; you can redistribute it and/or modify it under
-the terms of the GNU General Public License as published by the Free Software
-Foundation; version 2 of the License.
-
-This program is distributed in the hope that it will be useful, but WITHOUT
-ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
-FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
-
-You should have received a copy of the GNU General Public License along with
-this program; if not, write to the Free Software Foundation, Inc.,
-51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA
-
-*****************************************************************************/
-
-/**************************************************//**
-@file os/os0sync.cc
-The interface to the operating system
-synchronization primitives.
-
-Created 9/6/1995 Heikki Tuuri
-*******************************************************/
-
-#include "os0sync.h"
-#ifdef UNIV_NONINL
-#include "os0sync.ic"
-#endif
-
-#ifdef __WIN__
-#include <windows.h>
-#endif
-
-#include "ut0mem.h"
-#include "srv0start.h"
-#include "srv0srv.h"
-
-/* Type definition for an operating system mutex struct */
-struct os_mutex_t{
- os_event_t event; /*!< Used by sync0arr.cc for queing threads */
- void* handle; /*!< OS handle to mutex */
- ulint count; /*!< we use this counter to check
- that the same thread does not
- recursively lock the mutex: we
- do not assume that the OS mutex
- supports recursive locking, though
- NT seems to do that */
- UT_LIST_NODE_T(os_mutex_t) os_mutex_list;
- /* list of all 'slow' OS mutexes created */
-};
-
-/** Mutex protecting counts and the lists of OS mutexes and events */
-UNIV_INTERN os_ib_mutex_t os_sync_mutex;
-/** TRUE if os_sync_mutex has been initialized */
-static ibool os_sync_mutex_inited = FALSE;
-/** TRUE when os_sync_free() is being executed */
-static ibool os_sync_free_called = FALSE;
-
-/** This is incremented by 1 in os_thread_create and decremented by 1 in
-os_thread_exit */
-UNIV_INTERN ulint os_thread_count = 0;
-
-/** The list of all events created */
-static UT_LIST_BASE_NODE_T(os_event) os_event_list;
-
-/** The list of all OS 'slow' mutexes */
-static UT_LIST_BASE_NODE_T(os_mutex_t) os_mutex_list;
-
-UNIV_INTERN ulint os_event_count = 0;
-UNIV_INTERN ulint os_mutex_count = 0;
-UNIV_INTERN ulint os_fast_mutex_count = 0;
-
-/* The number of microsecnds in a second. */
-static const ulint MICROSECS_IN_A_SECOND = 1000000;
-
-#ifdef UNIV_PFS_MUTEX
-UNIV_INTERN mysql_pfs_key_t event_os_mutex_key;
-UNIV_INTERN mysql_pfs_key_t os_mutex_key;
-#endif
-
-/* Because a mutex is embedded inside an event and there is an
-event embedded inside a mutex, on free, this generates a recursive call.
-This version of the free event function doesn't acquire the global lock */
-static void os_event_free_internal(os_event_t event);
-
-/* On Windows (Vista and later), load function pointers for condition
-variable handling. Those functions are not available in prior versions,
-so we have to use them via runtime loading, as long as we support XP. */
-static void os_cond_module_init(void);
-
-#ifdef __WIN__
-/* Prototypes and function pointers for condition variable functions */
-typedef VOID (WINAPI* InitializeConditionVariableProc)
- (PCONDITION_VARIABLE ConditionVariable);
-static InitializeConditionVariableProc initialize_condition_variable;
-
-typedef BOOL (WINAPI* SleepConditionVariableCSProc)
- (PCONDITION_VARIABLE ConditionVariable,
- PCRITICAL_SECTION CriticalSection,
- DWORD dwMilliseconds);
-static SleepConditionVariableCSProc sleep_condition_variable;
-
-typedef VOID (WINAPI* WakeAllConditionVariableProc)
- (PCONDITION_VARIABLE ConditionVariable);
-static WakeAllConditionVariableProc wake_all_condition_variable;
-
-typedef VOID (WINAPI* WakeConditionVariableProc)
- (PCONDITION_VARIABLE ConditionVariable);
-static WakeConditionVariableProc wake_condition_variable;
-#endif
-
-/*********************************************************//**
-Initialitze condition variable */
-UNIV_INLINE
-void
-os_cond_init(
-/*=========*/
- os_cond_t* cond) /*!< in: condition variable. */
-{
- ut_a(cond);
-
-#ifdef __WIN__
- ut_a(initialize_condition_variable != NULL);
- initialize_condition_variable(cond);
-#else
- ut_a(pthread_cond_init(cond, NULL) == 0);
-#endif
-}
-
-/*********************************************************//**
-Do a timed wait on condition variable.
-@return TRUE if timed out, FALSE otherwise */
-UNIV_INLINE
-ibool
-os_cond_wait_timed(
-/*===============*/
- os_cond_t* cond, /*!< in: condition variable. */
- os_fast_mutex_t* fast_mutex, /*!< in: fast mutex */
-#ifndef __WIN__
- const struct timespec* abstime /*!< in: timeout */
-#else
- DWORD time_in_ms /*!< in: timeout in
- milliseconds*/
-#endif /* !__WIN__ */
-)
-{
- fast_mutex_t* mutex = &fast_mutex->mutex;
-#ifdef __WIN__
- BOOL ret;
- DWORD err;
-
- ut_a(sleep_condition_variable != NULL);
-
- ret = sleep_condition_variable(cond, mutex, time_in_ms);
-
- if (!ret) {
- err = GetLastError();
- /* From http://msdn.microsoft.com/en-us/library/ms686301%28VS.85%29.aspx,
- "Condition variables are subject to spurious wakeups
- (those not associated with an explicit wake) and stolen wakeups
- (another thread manages to run before the woken thread)."
- Check for both types of timeouts.
- Conditions are checked by the caller.*/
- if ((err == WAIT_TIMEOUT) || (err == ERROR_TIMEOUT)) {
- return(TRUE);
- }
- }
-
- ut_a(ret);
-
- return(FALSE);
-#else
- int ret;
-
- ret = pthread_cond_timedwait(cond, mutex, abstime);
-
- switch (ret) {
- case 0:
- case ETIMEDOUT:
- /* We play it safe by checking for EINTR even though
- according to the POSIX documentation it can't return EINTR. */
- case EINTR:
- break;
-
- default:
- fprintf(stderr, " InnoDB: pthread_cond_timedwait() returned: "
- "%d: abstime={%lu,%lu}\n",
- ret, (ulong) abstime->tv_sec, (ulong) abstime->tv_nsec);
- ut_error;
- }
-
- return(ret == ETIMEDOUT);
-#endif
-}
-/*********************************************************//**
-Wait on condition variable */
-UNIV_INLINE
-void
-os_cond_wait(
-/*=========*/
- os_cond_t* cond, /*!< in: condition variable. */
- os_fast_mutex_t* fast_mutex)/*!< in: fast mutex */
-{
- fast_mutex_t* mutex = &fast_mutex->mutex;
- ut_a(cond);
- ut_a(mutex);
-
-#ifdef __WIN__
- ut_a(sleep_condition_variable != NULL);
- ut_a(sleep_condition_variable(cond, mutex, INFINITE));
-#else
- ut_a(pthread_cond_wait(cond, mutex) == 0);
-#endif
-}
-
-/*********************************************************//**
-Wakes all threads waiting for condition variable */
-UNIV_INLINE
-void
-os_cond_broadcast(
-/*==============*/
- os_cond_t* cond) /*!< in: condition variable. */
-{
- ut_a(cond);
-
-#ifdef __WIN__
- ut_a(wake_all_condition_variable != NULL);
- wake_all_condition_variable(cond);
-#else
- ut_a(pthread_cond_broadcast(cond) == 0);
-#endif
-}
-
-/*********************************************************//**
-Destroys condition variable */
-UNIV_INLINE
-void
-os_cond_destroy(
-/*============*/
- os_cond_t* cond) /*!< in: condition variable. */
-{
-#ifdef __WIN__
- /* Do nothing */
-#else
- ut_a(pthread_cond_destroy(cond) == 0);
-#endif
-}
-
-/*********************************************************//**
-On Windows (Vista and later), load function pointers for condition variable
-handling. Those functions are not available in prior versions, so we have to
-use them via runtime loading, as long as we support XP. */
-static
-void
-os_cond_module_init(void)
-/*=====================*/
-{
-#ifdef __WIN__
- HMODULE h_dll;
-
- if (!srv_use_native_conditions)
- return;
-
- h_dll = GetModuleHandle("kernel32");
-
- initialize_condition_variable = (InitializeConditionVariableProc)
- GetProcAddress(h_dll, "InitializeConditionVariable");
- sleep_condition_variable = (SleepConditionVariableCSProc)
- GetProcAddress(h_dll, "SleepConditionVariableCS");
- wake_all_condition_variable = (WakeAllConditionVariableProc)
- GetProcAddress(h_dll, "WakeAllConditionVariable");
- wake_condition_variable = (WakeConditionVariableProc)
- GetProcAddress(h_dll, "WakeConditionVariable");
-
- /* When using native condition variables, check function pointers */
- ut_a(initialize_condition_variable);
- ut_a(sleep_condition_variable);
- ut_a(wake_all_condition_variable);
- ut_a(wake_condition_variable);
-#endif
-}
-
-/*********************************************************//**
-Initializes global event and OS 'slow' mutex lists. */
-UNIV_INTERN
-void
-os_sync_init(void)
-/*==============*/
-{
- UT_LIST_INIT(os_event_list);
- UT_LIST_INIT(os_mutex_list);
-
- os_sync_mutex = NULL;
- os_sync_mutex_inited = FALSE;
-
- /* Now for Windows only */
- os_cond_module_init();
-
- os_sync_mutex = os_mutex_create();
-
- os_sync_mutex_inited = TRUE;
-}
-
-/*********************************************************//**
-Frees created events and OS 'slow' mutexes. */
-UNIV_INTERN
-void
-os_sync_free(void)
-/*==============*/
-{
- os_event_t event;
- os_ib_mutex_t mutex;
-
- os_sync_free_called = TRUE;
- event = UT_LIST_GET_FIRST(os_event_list);
-
- while (event) {
-
- os_event_free(event);
-
- event = UT_LIST_GET_FIRST(os_event_list);
- }
-
- mutex = UT_LIST_GET_FIRST(os_mutex_list);
-
- while (mutex) {
- if (mutex == os_sync_mutex) {
- /* Set the flag to FALSE so that we do not try to
- reserve os_sync_mutex any more in remaining freeing
- operations in shutdown */
- os_sync_mutex_inited = FALSE;
- }
-
- os_mutex_free(mutex);
-
- mutex = UT_LIST_GET_FIRST(os_mutex_list);
- }
- os_sync_free_called = FALSE;
-}
-
-/*********************************************************//**
-Creates an event semaphore, i.e., a semaphore which may just have two
-states: signaled and nonsignaled. The created event is manual reset: it
-must be reset explicitly by calling sync_os_reset_event.
-@return the event handle */
-UNIV_INTERN
-os_event_t
-os_event_create(void)
-/*==================*/
-{
- os_event_t event;
-
-#ifdef __WIN__
- if(!srv_use_native_conditions) {
-
- event = static_cast<os_event_t>(ut_malloc(sizeof(*event)));
-
- event->handle = CreateEvent(NULL, TRUE, FALSE, NULL);
- if (!event->handle) {
- fprintf(stderr,
- "InnoDB: Could not create a Windows event"
- " semaphore; Windows error %lu\n",
- (ulong) GetLastError());
- }
- } else /* Windows with condition variables */
-#endif
- {
- event = static_cast<os_event_t>(ut_malloc(sizeof *event));
-
-#ifndef PFS_SKIP_EVENT_MUTEX
- os_fast_mutex_init(event_os_mutex_key, &event->os_mutex);
-#else
- os_fast_mutex_init(PFS_NOT_INSTRUMENTED, &event->os_mutex);
-#endif
-
- os_cond_init(&(event->cond_var));
-
- event->is_set = FALSE;
-
- /* We return this value in os_event_reset(), which can then be
- be used to pass to the os_event_wait_low(). The value of zero
- is reserved in os_event_wait_low() for the case when the
- caller does not want to pass any signal_count value. To
- distinguish between the two cases we initialize signal_count
- to 1 here. */
- event->signal_count = 1;
- }
-
- /* The os_sync_mutex can be NULL because during startup an event
- can be created [ because it's embedded in the mutex/rwlock ] before
- this module has been initialized */
- if (os_sync_mutex != NULL) {
- os_mutex_enter(os_sync_mutex);
- }
-
- /* Put to the list of events */
- UT_LIST_ADD_FIRST(os_event_list, os_event_list, event);
-
- os_event_count++;
-
- if (os_sync_mutex != NULL) {
- os_mutex_exit(os_sync_mutex);
- }
-
- return(event);
-}
-
-/**********************************************************//**
-Sets an event semaphore to the signaled state: lets waiting threads
-proceed. */
-UNIV_INTERN
-void
-os_event_set(
-/*=========*/
- os_event_t event) /*!< in: event to set */
-{
- ut_a(event);
-
-#ifdef __WIN__
- if (!srv_use_native_conditions) {
- ut_a(SetEvent(event->handle));
- return;
- }
-#endif
-
- os_fast_mutex_lock(&(event->os_mutex));
-
- if (event->is_set) {
- /* Do nothing */
- } else {
- event->is_set = TRUE;
- event->signal_count += 1;
- os_cond_broadcast(&(event->cond_var));
- }
-
- os_fast_mutex_unlock(&(event->os_mutex));
-}
-
-/**********************************************************//**
-Resets an event semaphore to the nonsignaled state. Waiting threads will
-stop to wait for the event.
-The return value should be passed to os_even_wait_low() if it is desired
-that this thread should not wait in case of an intervening call to
-os_event_set() between this os_event_reset() and the
-os_event_wait_low() call. See comments for os_event_wait_low().
-@return current signal_count. */
-UNIV_INTERN
-ib_int64_t
-os_event_reset(
-/*===========*/
- os_event_t event) /*!< in: event to reset */
-{
- ib_int64_t ret = 0;
-
- ut_a(event);
-
-#ifdef __WIN__
- if(!srv_use_native_conditions) {
- ut_a(ResetEvent(event->handle));
- return(0);
- }
-#endif
-
- os_fast_mutex_lock(&(event->os_mutex));
-
- if (!event->is_set) {
- /* Do nothing */
- } else {
- event->is_set = FALSE;
- }
- ret = event->signal_count;
-
- os_fast_mutex_unlock(&(event->os_mutex));
- return(ret);
-}
-
-/**********************************************************//**
-Frees an event object, without acquiring the global lock. */
-static
-void
-os_event_free_internal(
-/*===================*/
- os_event_t event) /*!< in: event to free */
-{
-#ifdef __WIN__
- if(!srv_use_native_conditions) {
- ut_a(event);
- ut_a(CloseHandle(event->handle));
- } else
-#endif
- {
- ut_a(event);
-
- /* This is to avoid freeing the mutex twice */
- os_fast_mutex_free(&(event->os_mutex));
-
- os_cond_destroy(&(event->cond_var));
- }
-
- /* Remove from the list of events */
- UT_LIST_REMOVE(os_event_list, os_event_list, event);
-
- os_event_count--;
-
- ut_free(event);
-}
-
-/**********************************************************//**
-Frees an event object. */
-UNIV_INTERN
-void
-os_event_free(
-/*==========*/
- os_event_t event) /*!< in: event to free */
-
-{
- ut_a(event);
-#ifdef __WIN__
- if(!srv_use_native_conditions){
- ut_a(CloseHandle(event->handle));
- } else /*Windows with condition variables */
-#endif
- {
- os_fast_mutex_free(&(event->os_mutex));
-
- os_cond_destroy(&(event->cond_var));
- }
-
- /* Remove from the list of events */
- os_mutex_enter(os_sync_mutex);
-
- UT_LIST_REMOVE(os_event_list, os_event_list, event);
-
- os_event_count--;
-
- os_mutex_exit(os_sync_mutex);
-
- ut_free(event);
-}
-
-/**********************************************************//**
-Waits for an event object until it is in the signaled state.
-
-Typically, if the event has been signalled after the os_event_reset()
-we'll return immediately because event->is_set == TRUE.
-There are, however, situations (e.g.: sync_array code) where we may
-lose this information. For example:
-
-thread A calls os_event_reset()
-thread B calls os_event_set() [event->is_set == TRUE]
-thread C calls os_event_reset() [event->is_set == FALSE]
-thread A calls os_event_wait() [infinite wait!]
-thread C calls os_event_wait() [infinite wait!]
-
-Where such a scenario is possible, to avoid infinite wait, the
-value returned by os_event_reset() should be passed in as
-reset_sig_count. */
-UNIV_INTERN
-void
-os_event_wait_low(
-/*==============*/
- os_event_t event, /*!< in: event to wait */
- ib_int64_t reset_sig_count)/*!< in: zero or the value
- returned by previous call of
- os_event_reset(). */
-{
-#ifdef __WIN__
- if(!srv_use_native_conditions) {
- DWORD err;
-
- ut_a(event);
-
- UT_NOT_USED(reset_sig_count);
-
- /* Specify an infinite wait */
- err = WaitForSingleObject(event->handle, INFINITE);
-
- ut_a(err == WAIT_OBJECT_0);
- return;
- }
-#endif
-
- os_fast_mutex_lock(&event->os_mutex);
-
- if (!reset_sig_count) {
- reset_sig_count = event->signal_count;
- }
-
- while (!event->is_set && event->signal_count == reset_sig_count) {
- os_cond_wait(&(event->cond_var), &(event->os_mutex));
-
- /* Solaris manual said that spurious wakeups may occur: we
- have to check if the event really has been signaled after
- we came here to wait */
- }
-
- os_fast_mutex_unlock(&event->os_mutex);
-}
-
-/**********************************************************//**
-Waits for an event object until it is in the signaled state or
-a timeout is exceeded.
-@return 0 if success, OS_SYNC_TIME_EXCEEDED if timeout was exceeded */
-UNIV_INTERN
-ulint
-os_event_wait_time_low(
-/*===================*/
- os_event_t event, /*!< in: event to wait */
- ulint time_in_usec, /*!< in: timeout in
- microseconds, or
- OS_SYNC_INFINITE_TIME */
- ib_int64_t reset_sig_count) /*!< in: zero or the value
- returned by previous call of
- os_event_reset(). */
-{
- ibool timed_out = FALSE;
-
-#ifdef __WIN__
- DWORD time_in_ms;
-
- if (!srv_use_native_conditions) {
- DWORD err;
-
- ut_a(event);
-
- if (time_in_usec != OS_SYNC_INFINITE_TIME) {
- time_in_ms = static_cast<DWORD>(time_in_usec / 1000);
- err = WaitForSingleObject(event->handle, time_in_ms);
- } else {
- err = WaitForSingleObject(event->handle, INFINITE);
- }
-
- if (err == WAIT_OBJECT_0) {
- return(0);
- } else if ((err == WAIT_TIMEOUT) || (err == ERROR_TIMEOUT)) {
- return(OS_SYNC_TIME_EXCEEDED);
- }
-
- ut_error;
- /* Dummy value to eliminate compiler warning. */
- return(42);
- } else {
- ut_a(sleep_condition_variable != NULL);
-
- if (time_in_usec != OS_SYNC_INFINITE_TIME) {
- time_in_ms = static_cast<DWORD>(time_in_usec / 1000);
- } else {
- time_in_ms = INFINITE;
- }
- }
-#else
- struct timespec abstime;
-
- if (time_in_usec != OS_SYNC_INFINITE_TIME) {
- struct timeval tv;
- int ret;
- ulint sec;
- ulint usec;
-
- ret = ut_usectime(&sec, &usec);
- ut_a(ret == 0);
-
- tv.tv_sec = sec;
- tv.tv_usec = usec;
-
- tv.tv_usec += time_in_usec;
-
- if ((ulint) tv.tv_usec >= MICROSECS_IN_A_SECOND) {
- tv.tv_sec += tv.tv_usec / MICROSECS_IN_A_SECOND;
- tv.tv_usec %= MICROSECS_IN_A_SECOND;
- }
-
- abstime.tv_sec = tv.tv_sec;
- abstime.tv_nsec = tv.tv_usec * 1000;
- } else {
- abstime.tv_nsec = 999999999;
- abstime.tv_sec = (time_t) ULINT_MAX;
- }
-
- ut_a(abstime.tv_nsec <= 999999999);
-
-#endif /* __WIN__ */
-
- os_fast_mutex_lock(&event->os_mutex);
-
- if (!reset_sig_count) {
- reset_sig_count = event->signal_count;
- }
-
- do {
- if (event->is_set || event->signal_count != reset_sig_count) {
-
- break;
- }
-
- timed_out = os_cond_wait_timed(
- &event->cond_var, &event->os_mutex,
-#ifndef __WIN__
- &abstime
-#else
- time_in_ms
-#endif /* !__WIN__ */
- );
-
- } while (!timed_out);
-
- os_fast_mutex_unlock(&event->os_mutex);
-
- return(timed_out ? OS_SYNC_TIME_EXCEEDED : 0);
-}
-
-/*********************************************************//**
-Creates an operating system mutex semaphore. Because these are slow, the
-mutex semaphore of InnoDB itself (ib_mutex_t) should be used where possible.
-@return the mutex handle */
-UNIV_INTERN
-os_ib_mutex_t
-os_mutex_create(void)
-/*=================*/
-{
- os_fast_mutex_t* mutex;
- os_ib_mutex_t mutex_str;
-
- mutex = static_cast<os_fast_mutex_t*>(
- ut_malloc(sizeof(os_fast_mutex_t)));
-
- os_fast_mutex_init(os_mutex_key, mutex);
-
- mutex_str = static_cast<os_ib_mutex_t>(ut_malloc(sizeof *mutex_str));
-
- mutex_str->handle = mutex;
- mutex_str->count = 0;
- mutex_str->event = os_event_create();
-
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- /* When creating os_sync_mutex itself we cannot reserve it */
- os_mutex_enter(os_sync_mutex);
- }
-
- UT_LIST_ADD_FIRST(os_mutex_list, os_mutex_list, mutex_str);
-
- os_mutex_count++;
-
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- os_mutex_exit(os_sync_mutex);
- }
-
- return(mutex_str);
-}
-
-/**********************************************************//**
-Acquires ownership of a mutex semaphore. */
-UNIV_INTERN
-void
-os_mutex_enter(
-/*===========*/
- os_ib_mutex_t mutex) /*!< in: mutex to acquire */
-{
- os_fast_mutex_lock(static_cast<os_fast_mutex_t*>(mutex->handle));
-
- (mutex->count)++;
-
- ut_a(mutex->count == 1);
-}
-
-/**********************************************************//**
-Releases ownership of a mutex. */
-UNIV_INTERN
-void
-os_mutex_exit(
-/*==========*/
- os_ib_mutex_t mutex) /*!< in: mutex to release */
-{
- ut_a(mutex);
-
- ut_a(mutex->count == 1);
-
- (mutex->count)--;
- os_fast_mutex_unlock(static_cast<os_fast_mutex_t*>(mutex->handle));
-}
-
-/**********************************************************//**
-Frees a mutex object. */
-UNIV_INTERN
-void
-os_mutex_free(
-/*==========*/
- os_ib_mutex_t mutex) /*!< in: mutex to free */
-{
- ut_a(mutex);
-
- if (UNIV_LIKELY(!os_sync_free_called)) {
- os_event_free_internal(mutex->event);
- }
-
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- os_mutex_enter(os_sync_mutex);
- }
-
- UT_LIST_REMOVE(os_mutex_list, os_mutex_list, mutex);
-
- os_mutex_count--;
-
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- os_mutex_exit(os_sync_mutex);
- }
-
- os_fast_mutex_free(static_cast<os_fast_mutex_t*>(mutex->handle));
- ut_free(mutex->handle);
- ut_free(mutex);
-}
-
-/*********************************************************//**
-Initializes an operating system fast mutex semaphore. */
-UNIV_INTERN
-void
-os_fast_mutex_init_func(
-/*====================*/
- fast_mutex_t* fast_mutex) /*!< in: fast mutex */
-{
-#ifdef __WIN__
- ut_a(fast_mutex);
-
- InitializeCriticalSection((LPCRITICAL_SECTION) fast_mutex);
-#else
- ut_a(0 == pthread_mutex_init(fast_mutex, MY_MUTEX_INIT_FAST));
-#endif
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- /* When creating os_sync_mutex itself (in Unix) we cannot
- reserve it */
-
- os_mutex_enter(os_sync_mutex);
- }
-
- os_fast_mutex_count++;
-
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- os_mutex_exit(os_sync_mutex);
- }
-}
-
-/**********************************************************//**
-Acquires ownership of a fast mutex. */
-UNIV_INTERN
-void
-os_fast_mutex_lock_func(
-/*====================*/
- fast_mutex_t* fast_mutex) /*!< in: mutex to acquire */
-{
-#ifdef __WIN__
- EnterCriticalSection((LPCRITICAL_SECTION) fast_mutex);
-#else
- pthread_mutex_lock(fast_mutex);
-#endif
-}
-
-/**********************************************************//**
-Releases ownership of a fast mutex. */
-UNIV_INTERN
-void
-os_fast_mutex_unlock_func(
-/*======================*/
- fast_mutex_t* fast_mutex) /*!< in: mutex to release */
-{
-#ifdef __WIN__
- LeaveCriticalSection(fast_mutex);
-#else
- pthread_mutex_unlock(fast_mutex);
-#endif
-}
-
-/**********************************************************//**
-Releases ownership of a fast mutex. Implies a full memory barrier even on
-platforms such as PowerPC where this is not normally required. */
-UNIV_INTERN
-void
-os_fast_mutex_unlock_full_barrier(
-/*=================*/
- os_fast_mutex_t* fast_mutex) /*!< in: mutex to release */
-{
-#ifdef __WIN__
- LeaveCriticalSection(&fast_mutex->mutex);
-#else
- pthread_mutex_unlock(&fast_mutex->mutex);
-#ifdef __powerpc__
- os_mb;
-#endif
-#endif
-}
-
-/**********************************************************//**
-Frees a mutex object. */
-UNIV_INTERN
-void
-os_fast_mutex_free_func(
-/*====================*/
- fast_mutex_t* fast_mutex) /*!< in: mutex to free */
-{
-#ifdef __WIN__
- ut_a(fast_mutex);
-
- DeleteCriticalSection((LPCRITICAL_SECTION) fast_mutex);
-#else
- int ret;
-
- ret = pthread_mutex_destroy(fast_mutex);
-
- if (UNIV_UNLIKELY(ret != 0)) {
- ut_print_timestamp(stderr);
- fprintf(stderr,
- " InnoDB: error: return value %lu when calling\n"
- "InnoDB: pthread_mutex_destroy().\n", (ulint) ret);
- fprintf(stderr,
- "InnoDB: Byte contents of the pthread mutex at %p:\n",
- (void*) fast_mutex);
- ut_print_buf(stderr, fast_mutex, sizeof(os_fast_mutex_t));
- putc('\n', stderr);
- }
-#endif
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- /* When freeing the last mutexes, we have
- already freed os_sync_mutex */
-
- os_mutex_enter(os_sync_mutex);
- }
-
- ut_ad(os_fast_mutex_count > 0);
- os_fast_mutex_count--;
-
- if (UNIV_LIKELY(os_sync_mutex_inited)) {
- os_mutex_exit(os_sync_mutex);
- }
-}
diff --git a/storage/innobase/os/os0thread.cc b/storage/innobase/os/os0thread.cc
index da2a2f59616..811bd87cef7 100644
--- a/storage/innobase/os/os0thread.cc
+++ b/storage/innobase/os/os0thread.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -187,17 +187,12 @@ os_thread_create_func(
if (thread_id != NULL) {
*thread_id = new_thread_id;
}
-
return((os_thread_t)new_thread_id);
}
-/*****************************************************************//**
-Exits the current thread. */
+/** Exits the current thread. */
void
-os_thread_exit(
-/*===========*/
- void* exit_value) /*!< in: exit value; in Windows this void*
- is cast as a DWORD */
+os_thread_exit()
{
#ifdef UNIV_DEBUG_THREAD_CREATION
ib::info() << "Thread exits, id "
@@ -221,11 +216,11 @@ os_thread_exit(
mutex_exit(&thread_mutex);
- ExitThread((DWORD) exit_value);
+ ExitThread(0);
#else
mutex_exit(&thread_mutex);
pthread_detach(pthread_self());
- pthread_exit(exit_value);
+ pthread_exit(NULL);
#endif
}
diff --git a/storage/innobase/page/page0zip.cc b/storage/innobase/page/page0zip.cc
index 167fc73a6d1..35ae10fc1bb 100644
--- a/storage/innobase/page/page0zip.cc
+++ b/storage/innobase/page/page0zip.cc
@@ -51,6 +51,8 @@ const byte field_ref_zero[FIELD_REF_SIZE] = {
#include "zlib.h"
#ifndef UNIV_HOTBACKUP
# include "buf0buf.h"
+#include "buf0types.h"
+#include "buf0checksum.h"
# include "btr0sea.h"
# include "dict0boot.h"
# include "lock0lock.h"
@@ -176,6 +178,56 @@ page_zip_empty_size(
- compressBound(static_cast<uLong>(2 * (n_fields + 1)));
return(size > 0 ? (ulint) size : 0);
}
+
+/** Check whether a tuple is too big for compressed table
+@param[in] index dict index object
+@param[in] entry entry for the index
+@return true if it's too big, otherwise false */
+bool
+page_zip_is_too_big(
+ const dict_index_t* index,
+ const dtuple_t* entry)
+{
+ const page_size_t& page_size =
+ dict_table_page_size(index->table);
+
+ /* Estimate the free space of an empty compressed page.
+ Subtract one byte for the encoded heap_no in the
+ modification log. */
+ ulint free_space_zip = page_zip_empty_size(
+ index->n_fields, page_size.physical());
+ ulint n_uniq = dict_index_get_n_unique_in_tree(index);
+
+ ut_ad(dict_table_is_comp(index->table));
+ ut_ad(page_size.is_compressed());
+
+ if (free_space_zip == 0) {
+ return(true);
+ }
+
+ /* Subtract one byte for the encoded heap_no in the
+ modification log. */
+ free_space_zip--;
+
+ /* There should be enough room for two node pointer
+ records on an empty non-leaf page. This prevents
+ infinite page splits. */
+
+ if (entry->n_fields >= n_uniq
+ && (REC_NODE_PTR_SIZE
+ + rec_get_converted_size_comp_prefix(
+ index, entry->fields, n_uniq, NULL)
+ /* On a compressed page, there is
+ a two-byte entry in the dense
+ page directory for every record.
+ But there is no record header. */
+ - (REC_N_NEW_EXTRA_BYTES - 2)
+ > free_space_zip / 2)) {
+ return(true);
+ }
+
+ return(false);
+}
#endif /* !UNIV_HOTBACKUP */
/*************************************************************//**
@@ -1760,7 +1812,7 @@ page_zip_fields_decode(
/**********************************************************************//**
Populate the sparse page directory from the dense directory.
@return TRUE on success, FALSE on failure */
-static __attribute__((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
ibool
page_zip_dir_decode(
/*================*/
@@ -3670,7 +3722,6 @@ page_zip_write_rec(
ulint heap_no;
byte* slot;
- ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip_get_size(page_zip)
> PAGE_DATA + page_zip_dir_size(page_zip));
@@ -3922,7 +3973,6 @@ page_zip_write_blob_ptr(
ut_ad(rec != NULL);
ut_ad(index != NULL);
ut_ad(offsets != NULL);
- ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
ut_ad(page_simple_validate_new((page_t*) page));
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip_get_size(page_zip)
@@ -4075,7 +4125,6 @@ page_zip_write_node_ptr(
page_t* page = page_align(rec);
#endif /* UNIV_DEBUG */
- ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
ut_ad(page_simple_validate_new(page));
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip_get_size(page_zip)
@@ -4143,8 +4192,6 @@ page_zip_write_trx_id_and_roll_ptr(
#endif /* UNIV_DEBUG */
ulint len;
- ut_ad(PAGE_ZIP_MATCH(rec, page_zip));
-
ut_ad(page_simple_validate_new(page));
ut_ad(page_zip_simple_validate(page_zip));
ut_ad(page_zip_get_size(page_zip)
@@ -4904,6 +4951,8 @@ corrupt:
@param[in] use_legacy_big_endian only used if algo is
SRV_CHECKSUM_ALGORITHM_CRC32 or SRV_CHECKSUM_ALGORITHM_STRICT_CRC32 - if true
then use big endian byteorder when converting byte strings to integers.
+SRV_CHECKSUM_ALGORITHM_CRC32 or SRV_CHECKSUM_ALGORITHM_STRICT_CRC32 - if true
+then use big endian byteorder when converting byte strings to integers.
@return page checksum */
uint32_t
page_zip_calc_checksum(
@@ -5076,6 +5125,8 @@ page_zip_verify_checksum(
return(TRUE);
}
+ bool legacy_checksum_checked = false;
+
switch (curr_algo) {
case SRV_CHECKSUM_ALGORITHM_STRICT_CRC32:
case SRV_CHECKSUM_ALGORITHM_CRC32:
@@ -5094,9 +5145,18 @@ page_zip_verify_checksum(
return(TRUE);
}
- if (stored == page_zip_calc_checksum(data, size, curr_algo,
- true)) {
- return(TRUE);
+ /* We need to check whether the stored checksum matches legacy
+ big endian checksum or Innodb checksum. We optimize the order
+ based on earlier results. if earlier we have found pages
+ matching legacy big endian checksum, we try to match it first.
+ Otherwise we check innodb checksum first. */
+ if (legacy_big_endian_checksum) {
+ if (stored == page_zip_calc_checksum(
+ data, size, curr_algo, true)) {
+
+ return(TRUE);
+ }
+ legacy_checksum_checked = true;
}
if (stored == page_zip_calc_checksum(
@@ -5115,6 +5175,15 @@ page_zip_verify_checksum(
return(TRUE);
}
+ /* If legacy checksum is not checked, do it now. */
+ if (!legacy_checksum_checked
+ && stored == page_zip_calc_checksum(
+ data, size, curr_algo, true)) {
+
+ legacy_big_endian_checksum = true;
+ return(TRUE);
+ }
+
break;
case SRV_CHECKSUM_ALGORITHM_STRICT_INNODB:
case SRV_CHECKSUM_ALGORITHM_INNODB:
diff --git a/storage/innobase/pars/lexyy.cc b/storage/innobase/pars/lexyy.cc
index 85fbbd33b9d..b97afd7c76b 100644
--- a/storage/innobase/pars/lexyy.cc
+++ b/storage/innobase/pars/lexyy.cc
@@ -2663,7 +2663,7 @@ void yyrestart (FILE * input_file )
* @param new_buffer The new input buffer.
*
*/
- MY_ATTRIBUTE((unused)) static void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+MY_ATTRIBUTE((unused)) static void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
{
/* TODO. We should be able to replace this entire function body
diff --git a/storage/innobase/pars/pars0pars.cc b/storage/innobase/pars/pars0pars.cc
index ebee3d3eeea..36846e418b0 100644
--- a/storage/innobase/pars/pars0pars.cc
+++ b/storage/innobase/pars/pars0pars.cc
@@ -2037,7 +2037,7 @@ pars_procedure_definition(
fork = que_fork_create(NULL, NULL, QUE_FORK_PROCEDURE, heap);
fork->trx = NULL;
- thr = que_thr_create(fork, heap);
+ thr = que_thr_create(fork, heap, NULL);
node = static_cast<proc_node_t*>(
mem_heap_alloc(heap, sizeof(proc_node_t)));
@@ -2172,18 +2172,21 @@ pars_sql(
return(graph);
}
-/******************************************************************//**
-Completes a query graph by adding query thread and fork nodes
+/** Completes a query graph by adding query thread and fork nodes
above it and prepares the graph for running. The fork created is of
type QUE_FORK_MYSQL_INTERFACE.
+@param[in] node root node for an incomplete query
+ graph, or NULL for dummy graph
+@param[in] trx transaction handle
+@param[in] heap memory heap from which allocated
+@param[in] prebuilt row prebuilt structure
@return query thread node to run */
que_thr_t*
pars_complete_graph_for_exec(
-/*=========================*/
- que_node_t* node, /*!< in: root node for an incomplete
- query graph, or NULL for dummy graph */
- trx_t* trx, /*!< in: transaction handle */
- mem_heap_t* heap) /*!< in: memory heap from which allocated */
+ que_node_t* node,
+ trx_t* trx,
+ mem_heap_t* heap,
+ row_prebuilt_t* prebuilt)
{
que_fork_t* fork;
que_thr_t* thr;
@@ -2191,7 +2194,7 @@ pars_complete_graph_for_exec(
fork = que_fork_create(NULL, NULL, QUE_FORK_MYSQL_INTERFACE, heap);
fork->trx = trx;
- thr = que_thr_create(fork, heap);
+ thr = que_thr_create(fork, heap, prebuilt);
thr->child = node;
diff --git a/storage/innobase/que/que0que.cc b/storage/innobase/que/que0que.cc
index 2f7e78ec378..8d3e8cfa115 100644
--- a/storage/innobase/que/que0que.cc
+++ b/storage/innobase/que/que0que.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1996, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1996, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -153,14 +153,17 @@ que_fork_create(
return(fork);
}
-/***********************************************************************//**
-Creates a query graph thread node.
+
+/** Creates a query graph thread node.
+@param[in] parent parent node, i.e., a fork node
+@param[in] heap memory heap where created
+@param[in] prebuilt row prebuilt structure
@return own: query thread node */
que_thr_t*
que_thr_create(
-/*===========*/
- que_fork_t* parent, /*!< in: parent node, i.e., a fork node */
- mem_heap_t* heap) /*!< in: memory heap where created */
+ que_fork_t* parent,
+ mem_heap_t* heap,
+ row_prebuilt_t* prebuilt)
{
que_thr_t* thr;
@@ -181,6 +184,8 @@ que_thr_create(
thr->lock_state = QUE_THR_LOCK_NOLOCK;
+ thr->prebuilt = prebuilt;
+
UT_LIST_ADD_LAST(parent->thrs, thr);
return(thr);
@@ -905,7 +910,7 @@ que_node_get_containing_loop_node(
#ifndef DBUG_OFF
/** Gets information of an SQL query graph node.
@return type description */
-static __attribute__((warn_unused_result, nonnull))
+static MY_ATTRIBUTE((warn_unused_result, nonnull))
const char*
que_node_type_string(
/*=================*/
diff --git a/storage/innobase/rem/rem0cmp.cc b/storage/innobase/rem/rem0cmp.cc
index f1a35d45e63..9cd0f76c7a9 100644
--- a/storage/innobase/rem/rem0cmp.cc
+++ b/storage/innobase/rem/rem0cmp.cc
@@ -587,6 +587,51 @@ cmp_dtuple_rec_with_gis(
return(ret);
}
+/** Compare a GIS data tuple to a physical record in rtree non-leaf node.
+We need to check the page number field, since we don't store pk field in
+rtree non-leaf node.
+@param[in] dtuple data tuple
+@param[in] rec R-tree record
+@param[in] offsets rec_get_offsets(rec)
+@retval negative if dtuple is less than rec */
+int
+cmp_dtuple_rec_with_gis_internal(
+ const dtuple_t* dtuple,
+ const rec_t* rec,
+ const ulint* offsets)
+{
+ const dfield_t* dtuple_field; /* current field in logical record */
+ ulint dtuple_f_len; /* the length of the current field
+ in the logical record */
+ ulint rec_f_len; /* length of current field in rec */
+ const byte* rec_b_ptr; /* pointer to the current byte in
+ rec field */
+ int ret = 0; /* return value */
+
+ dtuple_field = dtuple_get_nth_field(dtuple, 0);
+ dtuple_f_len = dfield_get_len(dtuple_field);
+
+ rec_b_ptr = rec_get_nth_field(rec, offsets, 0, &rec_f_len);
+ ret = cmp_gis_field(
+ PAGE_CUR_WITHIN,
+ static_cast<const byte*>(dfield_get_data(dtuple_field)),
+ (unsigned) dtuple_f_len, rec_b_ptr, (unsigned) rec_f_len);
+ if (ret != 0) {
+ return(ret);
+ }
+
+ dtuple_field = dtuple_get_nth_field(dtuple, 1);
+ dtuple_f_len = dfield_get_len(dtuple_field);
+ rec_b_ptr = rec_get_nth_field(rec, offsets, 1, &rec_f_len);
+
+ return(cmp_data(dtuple_field->type.mtype,
+ dtuple_field->type.prtype,
+ static_cast<const byte*>(dtuple_field->data),
+ dtuple_f_len,
+ rec_b_ptr,
+ rec_f_len));
+}
+
/** Compare two data fields.
@param[in] mtype main type
@param[in] prtype precise type
@@ -631,8 +676,6 @@ cmp_dtuple_rec_with_match_low(
ulint cur_field; /* current field number */
int ret; /* return value */
- ut_ad(rec != NULL);
- ut_ad(matched_fields != NULL);
ut_ad(dtuple_check_typed(dtuple));
ut_ad(rec_offs_validate(rec, NULL, offsets));
@@ -1140,15 +1183,6 @@ cmp_rec_rec_with_match(
break;
}
- /* If this is comparing non-leaf node record on Rtree,
- then avoid comparing node-ptr field.*/
- if (dict_index_is_spatial(index)
- && cur_field == DICT_INDEX_SPATIAL_NODEPTR_SIZE
- && (!page_is_leaf(page_align(rec1))
- || !page_is_leaf(page_align(rec2)))) {
- break;
- }
-
if (dict_index_is_ibuf(index)) {
/* This is for the insert buffer B-tree. */
mtype = DATA_BINARY;
@@ -1206,8 +1240,6 @@ order_resolved:
}
#ifdef UNIV_COMPILE_TEST_FUNCS
- ut_ad(rec != NULL);
- ut_ad(matched_fields != NULL);
#ifdef HAVE_UT_CHRONO_T
diff --git a/storage/innobase/rem/rem0rec.cc b/storage/innobase/rem/rem0rec.cc
index 607c8be3627..d055aa5d84e 100644
--- a/storage/innobase/rem/rem0rec.cc
+++ b/storage/innobase/rem/rem0rec.cc
@@ -787,7 +787,7 @@ rec_get_nth_field_offs_old(
/**********************************************************//**
Determines the size of a data tuple prefix in ROW_FORMAT=COMPACT.
@return total size */
-UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(1)))
+UNIV_INLINE MY_ATTRIBUTE((warn_unused_result, nonnull(1,2)))
ulint
rec_get_converted_size_comp_prefix_low(
/*===================================*/
@@ -1678,8 +1678,15 @@ rec_copy_prefix_to_buf(
ut_ad(n_fields <= dict_index_get_n_fields(index));
break;
case REC_STATUS_NODE_PTR:
- /* it doesn't make sense to copy the child page number field */
- ut_ad(n_fields <= dict_index_get_n_unique_in_tree_nonleaf(index));
+ /* For R-tree, we need to copy the child page number field. */
+ if (dict_index_is_spatial(index)) {
+ ut_ad(n_fields == DICT_INDEX_SPATIAL_NODEPTR_SIZE + 1);
+ } else {
+ /* it doesn't make sense to copy the child page number
+ field */
+ ut_ad(n_fields <=
+ dict_index_get_n_unique_in_tree_nonleaf(index));
+ }
break;
case REC_STATUS_INFIMUM:
case REC_STATUS_SUPREMUM:
@@ -1912,7 +1919,7 @@ rec_print_old(
(ulong) len);
}
} else {
- fprintf(file, " SQL NULL, size %lu ",
+ fprintf(file, " SQL NULL, size " ULINTPF " ",
rec_get_nth_field_size(rec, i));
}
diff --git a/storage/innobase/row/row0ftsort.cc b/storage/innobase/row/row0ftsort.cc
index 79f53b2b0f6..0a1c84a226e 100644
--- a/storage/innobase/row/row0ftsort.cc
+++ b/storage/innobase/row/row0ftsort.cc
@@ -241,6 +241,8 @@ row_fts_psort_info_init(
crypt_data = NULL;
}
+ ut_ad(trx->mysql_thd != NULL);
+ const char* path = thd_innodb_tmpdir(trx->mysql_thd);
/* There will be FTS_NUM_AUX_INDEX number of "sort buckets" for
each parallel sort thread. Each "sort bucket" holds records for
a particular "FTS index partition" */
@@ -263,7 +265,8 @@ row_fts_psort_info_init(
psort_info[j].merge_buf[i] = row_merge_buf_create(
dup->index);
- if (row_merge_file_create(psort_info[j].merge_file[i]) < 0) {
+ if (row_merge_file_create(psort_info[j].merge_file[i],
+ path) < 0) {
goto func_exit;
}
@@ -359,7 +362,6 @@ row_fts_psort_info_destroy(
if (psort_info[j].crypt_alloc[i]) {
ut_free(psort_info[j].crypt_alloc[i]);
}
-
}
mutex_free(&psort_info[j].mutex);
@@ -804,6 +806,11 @@ fts_parallel_tokenization(
psort_info->psort_common->trx->mysql_thd);
*/
+ ut_ad(psort_info->psort_common->trx->mysql_thd != NULL);
+
+ const char* path = thd_innodb_tmpdir(
+ psort_info->psort_common->trx->mysql_thd);
+
ut_ad(psort_info);
buf = psort_info->merge_buf;
@@ -857,8 +864,7 @@ loop:
doc.text.f_str =
btr_copy_externally_stored_field(
&doc.text.f_len, data,
- page_size, data_len, blob_heap
- );
+ page_size, data_len, blob_heap);
} else {
doc.text.f_str = data;
doc.text.f_len = data_len;
@@ -1045,7 +1051,7 @@ exit:
continue;
}
- tmpfd[i] = row_merge_file_create_low();
+ tmpfd[i] = row_merge_file_create_low(path);
if (tmpfd[i] < 0) {
error = DB_OUT_OF_MEMORY;
goto func_exit;
@@ -1096,7 +1102,7 @@ func_exit:
CloseHandle((HANDLE)psort_info->thread_hdl);
#endif /*__WIN__ */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -1113,8 +1119,9 @@ row_fts_start_psort(
for (i = 0; i < fts_sort_pll_degree; i++) {
psort_info[i].psort_id = i;
- os_thread_create(fts_parallel_tokenization,
- (void*) &psort_info[i],
+ psort_info[i].thread_hdl =
+ os_thread_create(fts_parallel_tokenization,
+ (void*) &psort_info[i],
&thd_id);
}
}
@@ -1146,7 +1153,7 @@ fts_parallel_merge(
CloseHandle((HANDLE)psort_info->thread_hdl);
#endif /*__WIN__ */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -1166,9 +1173,8 @@ row_fts_start_parallel_merge(
merge_info[i].psort_id = i;
merge_info[i].child_status = 0;
- os_thread_create(
- fts_parallel_merge, (void*) &merge_info[i], &thd_id);
- merge_info[i].thread_hdl = thd_id;
+ merge_info[i].thread_hdl = os_thread_create(fts_parallel_merge,
+ (void*) &merge_info[i], &thd_id);
}
}
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 42fa133ae34..1ae11204f69 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -46,6 +46,10 @@ Created 2012-02-08 by Sunny Bains.
#include <vector>
+#ifdef HAVE_MY_AES_H
+#include <my_aes.h>
+#endif
+
/** The size of the buffer to use for IO. Note: os_file_read() doesn't expect
reads to fail. If you set the buffer size to be greater than a multiple of the
file size then it will assert. TODO: Fix this limitation of the IO functions.
@@ -120,7 +124,8 @@ struct row_import {
m_col_names(),
m_n_indexes(),
m_indexes(),
- m_missing(true) { }
+ m_missing(true),
+ m_cfp_missing(true) { }
~row_import() UNIV_NOTHROW;
@@ -215,6 +220,9 @@ struct row_import {
bool m_missing; /*!< true if a .cfg file was
found and was readable */
+
+ bool m_cfp_missing; /*!< true if a .cfp file was
+ found and was readable */
};
/** Use the page cursor to iterate over records in a block. */
@@ -610,6 +618,13 @@ struct FetchIndexRootPages : public AbstractCallback {
return(m_space);
}
+ /**
+ @retval the space flags of the tablespace being iterated over */
+ virtual ulint get_space_flags() const UNIV_NOTHROW
+ {
+ return(m_space_flags);
+ }
+
/** Check if the .ibd file row format is the same as the table's.
@param ibd_table_flags determined from space and page.
@return DB_SUCCESS or error code. */
@@ -838,6 +853,13 @@ public:
return(m_cfg->m_table->space);
}
+ /**
+ @retval the space flags of the tablespace being iterated over */
+ virtual ulint get_space_flags() const UNIV_NOTHROW
+ {
+ return(m_space_flags);
+ }
+
/** Called for each block as it is read from the file.
@param offset physical offset in the file
@param block block to convert, it is not from the buffer pool.
@@ -1925,8 +1947,8 @@ PageConverter::update_page(
switch (page_type = fil_page_get_type(get_frame(block))) {
case FIL_PAGE_TYPE_FSP_HDR:
- /* Work directly on the uncompressed page headers. */
ut_a(block->page.id.page_no() == 0);
+ /* Work directly on the uncompressed page headers. */
return(update_header(block));
case FIL_PAGE_INDEX:
@@ -2000,6 +2022,7 @@ PageConverter::validate(
return(IMPORT_PAGE_STATUS_CORRUPTED);
} else if (offset > 0 && page_get_page_no(page) == 0) {
+
/* The page is all zero: do nothing. We already checked
for all NULs in buf_page_is_corrupted() */
return(IMPORT_PAGE_STATUS_ALL_ZERO);
@@ -2154,6 +2177,9 @@ row_import_cleanup(
trx_commit_for_mysql(trx);
+ prebuilt->table->encryption_key = NULL;
+ prebuilt->table->encryption_iv = NULL;
+
row_mysql_unlock_data_dictionary(trx);
trx_free_for_mysql(trx);
@@ -3137,6 +3163,170 @@ row_import_read_cfg(
return(err);
}
+#ifdef MYSQL_ENCRYPTION
+/** Read the contents of the <tablespace>.cfp file.
+@param[in] table table
+@param[in] file file to read from
+@param[in] thd session
+@param[in] cfp contents of the .cfp file
+@return DB_SUCCESS or error code. */
+static
+dberr_t
+row_import_read_encryption_data(
+ dict_table_t* table,
+ FILE* file,
+ THD* thd,
+ row_import& import)
+{
+ byte row[sizeof(ib_uint32_t)];
+ ulint key_size;
+ byte transfer_key[ENCRYPTION_KEY_LEN];
+ byte encryption_key[ENCRYPTION_KEY_LEN];
+ byte encryption_iv[ENCRYPTION_KEY_LEN];
+ lint elen;
+
+ if (fread(&row, 1, sizeof(row), file) != sizeof(row)) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
+ errno, strerror(errno),
+ "while reading encrypton key size.");
+
+ return(DB_IO_ERROR);
+ }
+
+ key_size = mach_read_from_4(row);
+ if (key_size != ENCRYPTION_KEY_LEN) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
+ errno, strerror(errno),
+ "while parsing encryption key size.");
+
+ return(DB_IO_ERROR);
+ }
+
+ /* Read the transfer key. */
+ if (fread(transfer_key, 1, ENCRYPTION_KEY_LEN, file)
+ != ENCRYPTION_KEY_LEN) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while reading tranfer key.");
+
+ return(DB_IO_ERROR);
+ }
+
+ /* Read the encrypted key. */
+ if (fread(encryption_key, 1, ENCRYPTION_KEY_LEN, file)
+ != ENCRYPTION_KEY_LEN) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while reading encryption key.");
+
+ return(DB_IO_ERROR);
+ }
+
+ /* Read the encrypted iv. */
+ if (fread(encryption_iv, 1, ENCRYPTION_KEY_LEN, file)
+ != ENCRYPTION_KEY_LEN) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while reading encryption iv.");
+
+ return(DB_IO_ERROR);
+ }
+
+ table->encryption_key =
+ static_cast<byte*>(mem_heap_alloc(table->heap,
+ ENCRYPTION_KEY_LEN));
+
+ table->encryption_iv =
+ static_cast<byte*>(mem_heap_alloc(table->heap,
+ ENCRYPTION_KEY_LEN));
+ /* Decrypt tablespace key and iv. */
+ elen = my_aes_decrypt(
+ encryption_key,
+ ENCRYPTION_KEY_LEN,
+ table->encryption_key,
+ transfer_key,
+ ENCRYPTION_KEY_LEN,
+ my_aes_256_ecb, NULL, false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
+ errno, strerror(errno),
+ "while decrypt encryption key.");
+
+ return(DB_IO_ERROR);
+ }
+
+ elen = my_aes_decrypt(
+ encryption_iv,
+ ENCRYPTION_KEY_LEN,
+ table->encryption_iv,
+ transfer_key,
+ ENCRYPTION_KEY_LEN,
+ my_aes_256_ecb, NULL, false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_ERROR, ER_IO_READ_ERROR,
+ errno, strerror(errno),
+ "while decrypt encryption iv.");
+
+ return(DB_IO_ERROR);
+ }
+
+ return(DB_SUCCESS);
+}
+
+/** Read the contents of the <tablename>.cfp file.
+@param[in] table table
+@param[in] thd session
+@param[in] cfp contents of the .cfp file
+@return DB_SUCCESS or error code. */
+static
+dberr_t
+row_import_read_cfp(
+ dict_table_t* table,
+ THD* thd,
+ row_import& import)
+{
+ dberr_t err;
+ char name[OS_FILE_MAX_PATH];
+
+ /* Clear table encryption information. */
+ table->encryption_key = NULL;
+ table->encryption_iv = NULL;
+
+ srv_get_encryption_data_filename(table, name, sizeof(name));
+
+ FILE* file = fopen(name, "rb");
+
+ if (file == NULL) {
+ import.m_cfp_missing = true;
+
+ /* If there's no cfp file, we assume it's not an
+ encrpyted table. return directly. */
+
+ import.m_cfp_missing = true;
+
+ err = DB_SUCCESS;
+ } else {
+
+ import.m_cfp_missing = false;
+
+ err = row_import_read_encryption_data(table, file,
+ thd, import);
+ fclose(file);
+ }
+
+ return(err);
+}
+#endif /* MYSQL_ENCRYPTION */
+
/*****************************************************************//**
Update the <space, root page> of a table's indexes from the values
in the data dictionary.
@@ -3375,6 +3565,7 @@ row_import_for_mysql(
trx_t* trx;
ib_uint64_t autoinc = 0;
char* filepath = NULL;
+ ulint space_flags MY_ATTRIBUTE((unused));
/* The caller assured that this is not read_only_mode and that no
temorary tablespace is being imported. */
@@ -3497,11 +3688,48 @@ row_import_for_mysql(
}
}
+ space_flags = fetchIndexRootPages.get_space_flags();
+
} else {
rw_lock_s_unlock_gen(dict_operation_lock, 0);
}
- if (err != DB_SUCCESS) {
+ /* Try to read encryption information. */
+ if (err == DB_SUCCESS) {
+#ifdef MYSQL_ENCRYPTION
+ err = row_import_read_cfp(table, trx->mysql_thd, cfg);
+
+ /* If table is not set to encrypted, but the fsp flag
+ is not, then return error. */
+ if (!dict_table_is_encrypted(table)
+ && space_flags != 0
+ && FSP_FLAGS_GET_ENCRYPTION(space_flags)) {
+
+ ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Table is not marked as encrypted, but"
+ " the tablespace is marked as encrypted");
+
+ err = DB_ERROR;
+ return(row_import_error(prebuilt, trx, err));
+ }
+
+ /* If table is set to encrypted, but can't find
+ cfp file, then return error. */
+ if (cfg.m_cfp_missing== true
+ && ((space_flags != 0
+ && FSP_FLAGS_GET_ENCRYPTION(space_flags))
+ || dict_table_is_encrypted(table))) {
+ ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Table is in an encrypted tablespace, but"
+ " can't find the encryption meta-data file"
+ " in importing");
+ err = DB_ERROR;
+ return(row_import_error(prebuilt, trx, err));
+ }
+#endif /* MYSQL_ENCRYPTION */
+ } else {
return(row_import_error(prebuilt, trx, err));
}
@@ -3524,6 +3752,22 @@ row_import_for_mysql(
DBUG_EXECUTE_IF("ib_import_reset_space_and_lsn_failure",
err = DB_TOO_MANY_CONCURRENT_TRXS;);
+#ifdef MYSQL_ENCRYPTION
+ if (err == DB_IO_NO_ENCRYPT_TABLESPACE) {
+ char table_name[MAX_FULL_NAME_LEN + 1];
+
+ innobase_format_name(
+ table_name, sizeof(table_name),
+ table->name.m_name);
+
+ ib_errf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
+ ER_TABLE_SCHEMA_MISMATCH,
+ "Encryption attribute is no matched");
+
+ return(row_import_cleanup(prebuilt, trx, err));
+ }
+#endif /* MYSQL_ENCRYPTION */
+
if (err != DB_SUCCESS) {
char table_name[MAX_FULL_NAME_LEN + 1];
@@ -3577,10 +3821,17 @@ row_import_for_mysql(
we will not be writing any redo log for it before we have invoked
fil_space_set_imported() to declare it a persistent tablespace. */
+ ulint fsp_flags = dict_tf_to_fsp_flags(table->flags, false);
+
+#ifdef MYSQL_ENCRYPTION
+ if (table->encryption_key != NULL) {
+ fsp_flags |= FSP_FLAGS_MASK_ENCRYPTION;
+ }
+#endif /* MYSQL_ENCRYPTION */
+
err = fil_ibd_open(
true, true, FIL_TYPE_IMPORT, table->space,
- dict_tf_to_fsp_flags(table->flags, false),
- table->name.m_name, filepath, table);
+ fsp_flags, table->name.m_name, filepath, table);
DBUG_EXECUTE_IF("ib_import_open_tablespace_failure",
err = DB_TABLESPACE_NOT_FOUND;);
@@ -3597,6 +3848,17 @@ row_import_for_mysql(
return(row_import_cleanup(prebuilt, trx, err));
}
+#ifdef MYSQL_ENCRYPTION
+ /* For encrypted table, set encryption information. */
+ if (dict_table_is_encrypted(table)) {
+
+ err = fil_set_encryption(table->space,
+ Encryption::AES,
+ table->encryption_key,
+ table->encryption_iv);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
row_mysql_unlock_data_dictionary(trx);
ut_free(filepath);
@@ -3694,6 +3956,37 @@ row_import_for_mysql(
ib::info() << "Phase IV - Flush complete";
fil_space_set_imported(prebuilt->table->space);
+#ifdef MYSQL_ENCRYPTION
+ if (dict_table_is_encrypted(table)) {
+ fil_space_t* space;
+ mtr_t mtr;
+ byte encrypt_info[ENCRYPTION_INFO_SIZE_V2];
+
+ mtr_start(&mtr);
+
+ mtr.set_named_space(table->space);
+ space = mtr_x_lock_space(table->space, &mtr);
+
+ memset(encrypt_info, 0, ENCRYPTION_INFO_SIZE_V2);
+
+ if (!fsp_header_rotate_encryption(space,
+ encrypt_info,
+ &mtr)) {
+ mtr_commit(&mtr);
+ ib_senderrf(trx->mysql_thd, IB_LOG_LEVEL_ERROR,
+ ER_FILE_NOT_FOUND,
+ filepath, err, ut_strerr(err));
+
+ ut_free(filepath);
+ row_mysql_unlock_data_dictionary(trx);
+
+ return(row_import_cleanup(prebuilt, trx, err));
+ }
+
+ mtr_commit(&mtr);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
/* The dictionary latches will be released in in row_import_cleanup()
after the transaction commit, for both success and error. */
diff --git a/storage/innobase/row/row0ins.cc b/storage/innobase/row/row0ins.cc
index 05d2378b81e..397617e659c 100644
--- a/storage/innobase/row/row0ins.cc
+++ b/storage/innobase/row/row0ins.cc
@@ -348,7 +348,7 @@ row_ins_clust_index_entry_by_modify(
upd_t* update;
dberr_t err;
btr_cur_t* cursor = btr_pcur_get_btr_cur(pcur);
-
+ TABLE* mysql_table = NULL;
ut_ad(dict_index_is_clust(cursor->index));
rec = btr_cur_get_rec(cursor);
@@ -359,10 +359,14 @@ row_ins_clust_index_entry_by_modify(
/* Build an update vector containing all the fields to be modified;
NOTE that this vector may NOT contain system columns trx_id or
roll_ptr */
+ if (thr->prebuilt != NULL) {
+ mysql_table = thr->prebuilt->m_mysql_table;
+ ut_ad(thr->prebuilt->trx == thr_get_trx(thr));
+ }
update = row_upd_build_difference_binary(
cursor->index, entry, rec, NULL, true,
- thr_get_trx(thr), heap);
+ thr_get_trx(thr), heap, mysql_table);
if (mode != BTR_MODIFY_TREE) {
ut_ad((mode & ~BTR_ALREADY_S_LATCHED) == BTR_MODIFY_LEAF);
@@ -518,7 +522,6 @@ row_ins_cascade_calc_update_vec(
update = cascade->update;
update->info_bits = 0;
- update->n_fields = foreign->n_fields;
n_fields_updated = 0;
@@ -932,8 +935,122 @@ row_ins_invalidate_query_cache(
ulint len = strlen(name) + 1;
innobase_invalidate_query_cache(thr_get_trx(thr), name, len);
}
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+
+/** Fill virtual column information in cascade node for the child table.
+@param[out] cascade child update node
+@param[in] rec clustered rec of child table
+@param[in] index clustered index of child table
+@param[in] node parent update node
+@param[in] foreign foreign key information
+@param[out] err error code. */
+static
+void
+row_ins_foreign_fill_virtual(
+ upd_node_t* cascade,
+ const rec_t* rec,
+ dict_index_t* index,
+ upd_node_t* node,
+ dict_foreign_t* foreign,
+ dberr_t* err)
+{
+ THD* thd = current_thd;
+ row_ext_t* ext;
+ ulint offsets_[REC_OFFS_NORMAL_SIZE];
+ rec_offs_init(offsets_);
+ const ulint* offsets =
+ rec_get_offsets(rec, index, offsets_,
+ ULINT_UNDEFINED, &cascade->heap);
+ mem_heap_t* v_heap = NULL;
+ upd_t* update = cascade->update;
+ ulint n_v_fld = index->table->n_v_def;
+ ulint n_diff;
+ upd_field_t* upd_field;
+ dict_vcol_set* v_cols = foreign->v_cols;
+ update->old_vrow = row_build(
+ ROW_COPY_POINTERS, index, rec,
+ offsets, index->table, NULL, NULL,
+ &ext, cascade->heap);
+ n_diff = update->n_fields;
+
+ update->n_fields += n_v_fld;
+
+ if (index->table->vc_templ == NULL) {
+ /** This can occur when there is a cascading
+ delete or update after restart. */
+ innobase_init_vc_templ(index->table);
+ }
+
+ for (ulint i = 0; i < n_v_fld; i++) {
+
+ dict_v_col_t* col = dict_table_get_nth_v_col(
+ index->table, i);
+
+ dict_vcol_set::iterator it = v_cols->find(col);
+
+ if (it == v_cols->end()) {
+ continue;
+ }
+
+ dfield_t* vfield = innobase_get_computed_value(
+ update->old_vrow, col, index,
+ &v_heap, update->heap, NULL, thd, NULL,
+ NULL, NULL, NULL);
+
+ if (vfield == NULL) {
+ *err = DB_COMPUTE_VALUE_FAILED;
+ goto func_exit;
+ }
+
+ upd_field = upd_get_nth_field(update, n_diff);
+
+ upd_field->old_v_val = static_cast<dfield_t*>(
+ mem_heap_alloc(cascade->heap,
+ sizeof *upd_field->old_v_val));
+
+ dfield_copy(upd_field->old_v_val, vfield);
+
+ upd_field_set_v_field_no(upd_field, i, index);
+
+ if (node->is_delete
+ ? (foreign->type & DICT_FOREIGN_ON_DELETE_SET_NULL)
+ : (foreign->type & DICT_FOREIGN_ON_UPDATE_SET_NULL)) {
+
+ dfield_set_null(&upd_field->new_val);
+ }
+
+ if (!node->is_delete
+ && (foreign->type & DICT_FOREIGN_ON_UPDATE_CASCADE)) {
+
+ dfield_t* new_vfield = innobase_get_computed_value(
+ update->old_vrow, col, index,
+ &v_heap, update->heap, NULL, thd,
+ NULL, NULL, node->update, foreign);
+
+ if (new_vfield == NULL) {
+ *err = DB_COMPUTE_VALUE_FAILED;
+ goto func_exit;
+ }
+
+ dfield_copy(&(upd_field->new_val), new_vfield);
+ }
+
+ n_diff++;
+ }
+
+ update->n_fields = n_diff;
+ *err = DB_SUCCESS;
+
+func_exit:
+ if (v_heap) {
+ mem_heap_free(v_heap);
+ }
+}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
#ifdef WITH_WSREP
-dberr_t wsrep_append_foreign_key(trx_t *trx,
+dberr_t wsrep_append_foreign_key(trx_t *trx,
dict_foreign_t* foreign,
const rec_t* clust_rec,
dict_index_t* clust_index,
@@ -1225,6 +1342,19 @@ row_ins_foreign_check_on_constraint(
if (fts_col_affacted) {
cascade->fts_doc_id = doc_id;
}
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ if (foreign->v_cols != NULL
+ && foreign->v_cols->size() > 0) {
+ row_ins_foreign_fill_virtual(
+ cascade, clust_rec, clust_index,
+ node, foreign, &err);
+
+ if (err != DB_SUCCESS) {
+ goto nonstandard_exit_func;
+ }
+ }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
} else if (table->fts && cascade->is_delete) {
/* DICT_FOREIGN_ON_DELETE_CASCADE case */
for (i = 0; i < foreign->n_fields; i++) {
@@ -1253,6 +1383,20 @@ row_ins_foreign_check_on_constraint(
node, foreign, cascade->cascade_heap,
trx, &fts_col_affacted, cascade);
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ if (foreign->v_cols != NULL
+ && foreign->v_cols->size() > 0) {
+ row_ins_foreign_fill_virtual(
+ cascade, clust_rec, clust_index,
+ node, foreign, &err);
+
+ if (err != DB_SUCCESS) {
+ goto nonstandard_exit_func;
+ }
+ }
+#endif /* MYSQL_VIRTUAL_COLUMNS */
+
if (n_to_update == ULINT_UNDEFINED) {
err = DB_ROW_IS_REFERENCED;
@@ -2693,7 +2837,7 @@ row_ins_sorted_clust_index_entry(
@param[in] check whether to check
@param[in] search_mode flags
@return true if the index is to be dropped */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
row_ins_sec_mtr_start_and_check_if_aborted(
mtr_t* mtr,
@@ -2837,7 +2981,7 @@ row_ins_sec_index_entry_low(
rtr_init_rtr_info(&rtr_info, false, &cursor, index, false);
rtr_info_update_btr(&cursor, &rtr_info);
- btr_cur_search_to_nth_level(
+ err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_RTREE_INSERT,
search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
@@ -2852,7 +2996,7 @@ row_ins_sec_index_entry_low(
mtr.set_named_space(index->space);
search_mode &= ~BTR_MODIFY_LEAF;
search_mode |= BTR_MODIFY_TREE;
- btr_cur_search_to_nth_level(
+ err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_RTREE_INSERT,
search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
@@ -2871,7 +3015,7 @@ row_ins_sec_index_entry_low(
ut_ad(cursor.page_cur.block != NULL);
ut_ad(cursor.page_cur.block->made_dirty_with_no_latch);
} else {
- btr_cur_search_to_nth_level(
+ err = btr_cur_search_to_nth_level(
index, 0, entry, PAGE_CUR_LE,
search_mode,
&cursor, 0, __FILE__, __LINE__, &mtr);
diff --git a/storage/innobase/row/row0log.cc b/storage/innobase/row/row0log.cc
index df396ac1a7d..614df1e30d9 100644
--- a/storage/innobase/row/row0log.cc
+++ b/storage/innobase/row/row0log.cc
@@ -205,6 +205,8 @@ struct row_log_t {
old table */
ulint n_old_vcol;
/*!< number of virtual column in old table */
+ const char* path; /*!< where to create temporary file during
+ log operation */
};
/** Create the file or online log if it does not exist.
@@ -217,7 +219,7 @@ row_log_tmpfile(
{
DBUG_ENTER("row_log_tmpfile");
if (log->fd < 0) {
- log->fd = row_merge_file_create_low();
+ log->fd = row_merge_file_create_low(log->path);
DBUG_EXECUTE_IF("row_log_tmpfile_fail",
if (log->fd > 0)
row_merge_file_destroy_low(log->fd);
@@ -535,6 +537,20 @@ err_exit:
row_log_table_close_func(log, size, avail)
#endif /* UNIV_DEBUG */
+/** Check whether a virtual column is indexed in the new table being
+created during alter table
+@param[in] index cluster index
+@param[in] v_no virtual column number
+@return true if it is indexed, else false */
+bool
+row_log_col_is_indexed(
+ const dict_index_t* index,
+ ulint v_no)
+{
+ return(dict_table_get_nth_v_col(
+ index->online_log->table, v_no)->m_col.ord_part);
+}
+
/******************************************************//**
Logs a delete operation to a table that is being rebuilt.
This will be merged in row_log_table_apply_delete(). */
@@ -665,8 +681,8 @@ row_log_table_delete(
if (ventry->n_v_fields > 0) {
ulint v_extra;
mrec_size += rec_get_converted_size_temp(
- index, NULL, 0, ventry, &v_extra);
- }
+ new_index, NULL, 0, ventry, &v_extra);
+ }
if (byte* b = row_log_table_open(index->online_log,
mrec_size, &avail_size)) {
@@ -815,7 +831,7 @@ row_log_table_low_redundant(
if (o_ventry) {
mrec_size += rec_get_converted_size_temp(
- index, NULL, 0, ventry, &v_extra);
+ index, NULL, 0, o_ventry, &v_extra);
}
} else if (index->table->n_v_cols) {
mrec_size += 2;
@@ -893,7 +909,7 @@ row_log_table_low_redundant(
/******************************************************//**
Logs an insert or update to a table that is being rebuilt. */
-static MY_ATTRIBUTE((nonnull(1,2,4)))
+static
void
row_log_table_low(
/*==============*/
@@ -958,11 +974,11 @@ row_log_table_low(
if (ventry && ventry->n_v_fields > 0) {
ulint v_extra = 0;
mrec_size += rec_get_converted_size_temp(
- index, NULL, 0, ventry, &v_extra);
+ new_index, NULL, 0, ventry, &v_extra);
if (o_ventry) {
mrec_size += rec_get_converted_size_temp(
- index, NULL, 0, ventry, &v_extra);
+ new_index, NULL, 0, o_ventry, &v_extra);
}
} else if (index->table->n_v_cols) {
/* Always leave 2 bytes length marker for virtual column
@@ -1629,7 +1645,7 @@ row_log_table_apply_insert_low(
{
rec_printer p(row);
DBUG_PRINT("ib_alter_table",
- ("insert table %llu (index %llu): %s",
+ ("insert table " IB_ID_FMT " (index " IB_ID_FMT "): %s",
index->table->id, index->id,
p.str().c_str()));
}
@@ -1673,6 +1689,7 @@ row_log_table_apply_insert_low(
flags, BTR_MODIFY_TREE,
index, offsets_heap, heap, entry, trx_id, thr,
false);
+
/* Report correct index name for duplicate key error. */
if (error == DB_DUPLICATE_KEY) {
thr_get_trx(thr)->error_key_num = n_index;
@@ -1738,7 +1755,7 @@ row_log_table_apply_insert(
/******************************************************//**
Deletes a record from a table that is being rebuilt.
@return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((nonnull(1, 2, 5), warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_log_table_apply_delete_low(
/*===========================*/
@@ -1764,7 +1781,7 @@ row_log_table_apply_delete_low(
{
rec_printer p(btr_pcur_get_rec(pcur), offsets);
DBUG_PRINT("ib_alter_table",
- ("delete table %llu (index %llu): %s",
+ ("delete table " IB_ID_FMT " (index " IB_ID_FMT "): %s",
index->table->id, index->id,
p.str().c_str()));
}
@@ -2197,7 +2214,7 @@ func_exit_committed:
row, NULL, index, heap);
upd_t* update = row_upd_build_difference_binary(
index, entry, btr_pcur_get_rec(&pcur), cur_offsets,
- false, NULL, heap);
+ false, NULL, heap, dup->table);
if (!update->n_fields) {
/* Nothing to do. */
@@ -2254,7 +2271,7 @@ func_exit_committed:
rec_printer old(old_row);
rec_printer new_row(row);
DBUG_PRINT("ib_alter_table",
- ("update table %llu (index %llu): %s to %s",
+ ("update table " IB_ID_FMT " (index " IB_ID_FMT "): %s to %s",
index->table->id, index->id,
old.str().c_str(),
new_row.str().c_str()));
@@ -2751,7 +2768,7 @@ row_log_progress_inc_per_block()
ALTER TABLE. If not NULL, then stage->inc() will be called for each block
of log that is applied.
@return DB_SUCCESS, or error code on failure */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_log_table_apply_ops(
que_thr_t* thr,
@@ -3164,8 +3181,9 @@ row_log_allocate(
const dtuple_t* add_cols,
/*!< in: default values of
added columns, or NULL */
- const ulint* col_map)/*!< in: mapping of old column
+ const ulint* col_map,/*!< in: mapping of old column
numbers to new ones, or NULL if !table */
+ const char* path) /*!< in: where to create temporary file */
{
row_log_t* log;
DBUG_ENTER("row_log_allocate");
@@ -3199,6 +3217,7 @@ row_log_allocate(
log->tail.block = log->head.block = NULL;
log->head.blocks = log->head.bytes = 0;
log->head.total = 0;
+ log->path = path;
log->n_old_col = index->table->n_cols;
log->n_old_vcol = index->table->n_v_cols;
@@ -3283,7 +3302,7 @@ row_log_apply_op_low(
{
rec_printer p(entry);
DBUG_PRINT("ib_create_index",
- ("%s %s index %llu,%lu: %s",
+ ("%s %s index " IB_ID_FMT "," IB_ID_FMT ": %s",
op == ROW_OP_INSERT ? "insert" : "delete",
has_index_lock ? "locked" : "unlocked",
index->id, trx_id,
@@ -3613,7 +3632,7 @@ interrupted)
ALTER TABLE. If not NULL, then stage->inc() will be called for each block
of log that is applied.
@return DB_SUCCESS, or error code on failure */
-static MY_ATTRIBUTE((nonnull))
+static
dberr_t
row_log_apply_ops(
const trx_t* trx,
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index da48be090ec..8ab60656171 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -30,6 +30,10 @@ Completed by Sunny Bains and Marko Makela
#include "ha_prototypes.h"
+#include <math.h>
+
+#include "ha_prototypes.h"
+
#include "row0merge.h"
#include "row0ext.h"
#include "row0log.h"
@@ -352,6 +356,9 @@ row_merge_decrypt_buf(
return true;
}
+/* Maximum pending doc memory limit in bytes for a fts tokenization thread */
+#define FTS_PENDING_DOC_MEMORY_LIMIT 1000000
+
/** Insert sorted data tuples to the index.
@param[in] trx_id transaction identifier
@param[in] index index to be inserted
@@ -365,7 +372,7 @@ or NULL if fd, block will be used instead
ALTER TABLE. If not NULL stage->begin_phase_insert() will be called initially
and then stage->inc() will be called for each record that is processed.
@return DB_SUCCESS or error number */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_merge_insert_index_tuples(
trx_id_t trx_id,
@@ -583,6 +590,8 @@ row_merge_buf_redundant_convert(
row_merge_buf_redundant_convert()
@param[in,out] err set if error occurs
@param[in,out] v_heap heap memory to process data for virtual column
+@param[in,out] my_table mysql table object
+@param[in] trx transaction object
@return number of rows added, 0 if out of space */
static
ulint
@@ -597,7 +606,9 @@ row_merge_buf_add(
doc_id_t* doc_id,
mem_heap_t* conv_heap,
dberr_t* err,
- mem_heap_t** v_heap)
+ mem_heap_t** v_heap,
+ TABLE* my_table,
+ trx_t* trx)
{
ulint i;
const dict_index_t* index;
@@ -644,15 +655,18 @@ row_merge_buf_add(
for (i = 0; i < n_fields; i++, field++, ifield++) {
ulint len;
const dict_col_t* col;
- const dict_v_col_t* v_col = NULL;
ulint col_no;
ulint fixed_len;
const dfield_t* row_field;
col = ifield->col;
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ const dict_v_col_t* v_col = NULL;
if (dict_col_is_virtual(col)) {
v_col = reinterpret_cast<const dict_v_col_t*>(col);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
col_no = dict_col_get_no(col);
@@ -678,18 +692,21 @@ row_merge_buf_add(
} else {
/* Use callback to get the virtual column value */
if (dict_col_is_virtual(col)) {
+ #ifdef MYSQL_VIRTUAL_COLUMN
dict_index_t* clust_index
= dict_table_get_first_index(new_table);
row_field = innobase_get_computed_value(
- row, v_col, clust_index, NULL,
- v_heap, NULL, ifield, false);
+ row, v_col, clust_index,
+ v_heap, NULL, ifield, trx->mysql_thd,
+ my_table, old_table, NULL, NULL);
if (row_field == NULL) {
*err = DB_COMPUTE_VALUE_FAILED;
DBUG_RETURN(0);
}
dfield_copy(field, row_field);
+#endif /* MYSQL_VIRTUAL_COLUMN */
} else {
row_field = dtuple_get_nth_field(row, col_no);
dfield_copy(field, row_field);
@@ -808,7 +825,8 @@ row_merge_buf_add(
len = dfield_get_len(field);
}
}
- } else {
+ } else if (!dict_col_is_virtual(col)) {
+ /* Only non-virtual column are stored externally */
const byte* buf = row_ext_lookup(ext, col_no,
&len);
if (UNIV_LIKELY_NULL(buf)) {
@@ -1098,7 +1116,7 @@ row_merge_buf_write(
DBUG_PRINT("ib_merge_sort",
("%p,fd=%d,%lu %lu: %s",
reinterpret_cast<const void*>(b), of->fd,
- ulong(of->offset), ulong(i),
+ (ulint)of->offset, (ulint)i,
p.str().c_str()));
}
#endif
@@ -1116,7 +1134,7 @@ row_merge_buf_write(
DBUG_PRINT("ib_merge_sort",
("write %p,%d,%lu EOF",
reinterpret_cast<const void*>(b), of->fd,
- ulong(of->offset)));
+ (ulint)of->offset));
DBUG_VOID_RETURN;
}
@@ -1297,7 +1315,7 @@ row_merge_read_rec(
("read %p,%p,%d,%lu EOF\n",
reinterpret_cast<const void*>(b),
reinterpret_cast<const void*>(block),
- fd, ulong(*foffs)));
+ fd, ulint(*foffs)));
DBUG_RETURN(NULL);
}
@@ -1418,7 +1436,7 @@ func_exit:
("%p,%p,fd=%d,%lu: %s",
reinterpret_cast<const void*>(b),
reinterpret_cast<const void*>(block),
- fd, ulong(*foffs),
+ fd, ulint(*foffs),
p.str().c_str()));
}
#endif
@@ -1457,7 +1475,7 @@ row_merge_write_rec_low(
rec_printer p(mrec, 0, offsets);
DBUG_PRINT("ib_merge_sort",
("%p,fd=%d,%lu: %s",
- reinterpret_cast<const void*>(b), fd, ulong(foffs),
+ reinterpret_cast<const void*>(b), fd, ulint(foffs),
p.str().c_str()));
}
#endif
@@ -1574,7 +1592,7 @@ row_merge_write_eof(
("%p,%p,fd=%d,%lu",
reinterpret_cast<const void*>(b),
reinterpret_cast<const void*>(block),
- fd, ulong(*foffs)));
+ fd, ulint(*foffs)));
if (b == &block[0]) {
b+= ROW_MERGE_RESERVE_SIZE;
@@ -1600,15 +1618,17 @@ row_merge_write_eof(
}
/** Create a temporary file if it has not been created already.
-@param[in,out] tmpfd temporary file handle
+@param[in,out] tmpfd temporary file handle
+@param[in] path location for creating temporary file
@return file descriptor, or -1 on failure */
static MY_ATTRIBUTE((warn_unused_result))
int
row_merge_tmpfile_if_needed(
- int* tmpfd)
+ int* tmpfd,
+ const char* path)
{
if (*tmpfd < 0) {
- *tmpfd = row_merge_file_create_low();
+ *tmpfd = row_merge_file_create_low(path);
if (*tmpfd >= 0) {
MONITOR_ATOMIC_INC(MONITOR_ALTER_TABLE_SORT_FILES);
}
@@ -1620,18 +1640,20 @@ row_merge_tmpfile_if_needed(
/** Create a temporary file for merge sort if it was not created already.
@param[in,out] file merge file structure
@param[in] nrec number of records in the file
+@param[in] path location for creating temporary file
@return file descriptor, or -1 on failure */
static MY_ATTRIBUTE((warn_unused_result))
int
row_merge_file_create_if_needed(
merge_file_t* file,
int* tmpfd,
- ulint nrec)
+ ulint nrec,
+ const char* path)
{
ut_ad(file->fd < 0 || *tmpfd >=0);
- if (file->fd < 0 && row_merge_file_create(file) >= 0) {
+ if (file->fd < 0 && row_merge_file_create(file, path) >= 0) {
MONITOR_ATOMIC_INC(MONITOR_ALTER_TABLE_SORT_FILES);
- if (row_merge_tmpfile_if_needed(tmpfd) < 0) {
+ if (row_merge_tmpfile_if_needed(tmpfd, path) < 0) {
return(-1);
}
@@ -1787,6 +1809,8 @@ existing order
@param[in,out] stage performance schema accounting object, used by
ALTER TABLE. stage->n_pk_recs_inc() will be called for each record read and
stage->inc() will be called for each page read.
+@param[in] eval_table mysql table used to evaluate virtual column
+ value, see innobase_get_computed_value().
@return DB_SUCCESS or error */
static MY_ATTRIBUTE((warn_unused_result))
dberr_t
@@ -1813,7 +1837,9 @@ row_merge_read_clustered_index(
ut_stage_alter_t* stage,
float pct_cost,
fil_space_crypt_t* crypt_data,
- row_merge_block_t* crypt_block)
+ row_merge_block_t* crypt_block,
+ struct TABLE* eval_table)
+
{
dict_index_t* clust_index; /* Clustered index */
mem_heap_t* row_heap; /* Heap memory to create
@@ -1874,6 +1900,10 @@ row_merge_read_clustered_index(
dfield_t* prev_fields;
const ulint n_uniq = dict_index_get_n_unique(index[0]);
+ ut_ad(trx->mysql_thd != NULL);
+
+ const char* path = thd_innodb_tmpdir(trx->mysql_thd);
+
ut_ad(!skip_pk_sort || dict_index_is_clust(index[0]));
/* There is no previous tuple yet. */
prev_mtuple.fields = NULL;
@@ -2335,7 +2365,7 @@ write_buffers:
buf, fts_index, old_table, new_table,
psort_info, row, ext, &doc_id,
conv_heap, &err,
- &v_heap)))) {
+ &v_heap, eval_table, trx)))) {
/* If we are creating FTS index,
a single row can generate more
@@ -2508,6 +2538,10 @@ write_buffers:
clust_btr_bulk->release();
}
+ if (err != DB_SUCCESS) {
+ break;
+ }
+
if (row != NULL) {
/* Restore the cursor on the
previous clustered index record,
@@ -2605,10 +2639,18 @@ write_buffers:
new_table->space);
err = btr_bulk.finish(err);
+
+ DBUG_EXECUTE_IF(
+ "row_merge_insert_big_row",
+ err = DB_TOO_BIG_RECORD;);
+
+ if (err != DB_SUCCESS) {
+ break;
+ }
} else {
if (row_merge_file_create_if_needed(
file, tmpfd,
- buf->n_tuples) < 0) {
+ buf->n_tuples, path) < 0) {
err = DB_OUT_OF_MEMORY;
trx->error_key_num = i;
goto func_exit;
@@ -2648,7 +2690,7 @@ write_buffers:
buf, fts_index, old_table,
new_table, psort_info, row, ext,
&doc_id, conv_heap,
- &err, &v_heap)))) {
+ &err, &v_heap, table, trx)))) {
/* An empty buffer should have enough
room for at least one record. */
ut_error;
@@ -2688,8 +2730,11 @@ write_buffers:
}
func_exit:
- mtr_commit(&mtr);
-
+ /* row_merge_spatial_rows may have committed
+ the mtr before an error occurs. */
+ if (mtr.is_active()) {
+ mtr_commit(&mtr);
+ }
mem_heap_free(row_heap);
ut_free(nonnull);
@@ -2809,7 +2854,7 @@ wait_again:
/* Sync fts cache for other fts indexes to keep all
fts indexes consistent in sync_doc_id. */
err = fts_sync_table(const_cast<dict_table_t*>(new_table),
- false, true);
+ false, true, false);
if (err == DB_SUCCESS) {
fts_update_next_doc_id(
@@ -2879,7 +2924,7 @@ wait_again:
ALTER TABLE. If not NULL stage->inc() will be called for each record
processed.
@return DB_SUCCESS or error code */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_merge_blocks(
const row_merge_dup_t* dup,
@@ -2910,8 +2955,8 @@ row_merge_blocks(
DBUG_ENTER("row_merge_blocks");
DBUG_PRINT("ib_merge_sort",
("fd=%d,%lu+%lu to fd=%d,%lu",
- file->fd, ulong(*foffs0), ulong(*foffs1),
- of->fd, ulong(of->offset)));
+ file->fd, ulint(*foffs0), ulint(*foffs1),
+ of->fd, ulint(of->offset)));
heap = row_merge_heap_create(dup->index, &buf, &offsets0, &offsets1);
@@ -2997,7 +3042,7 @@ done1:
ALTER TABLE. If not NULL stage->inc() will be called for each record
processed.
@return TRUE on success, FALSE on failure */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
ibool
row_merge_blocks_copy(
const dict_index_t* index,
@@ -3023,8 +3068,8 @@ row_merge_blocks_copy(
DBUG_ENTER("row_merge_blocks_copy");
DBUG_PRINT("ib_merge_sort",
("fd=%d,%lu to fd=%d,%lu",
- file->fd, ulong(foffs0),
- of->fd, ulong(of->offset)));
+ file->fd, ulint(foffs0),
+ of->fd, ulint(of->offset)));
heap = row_merge_heap_create(index, &buf, &offsets0, &offsets1);
@@ -3246,7 +3291,7 @@ row_merge_sort(
fil_space_crypt_t* crypt_data,/*!< in: table crypt data */
row_merge_block_t* crypt_block, /*!< in: crypt buf or NULL */
ulint space, /*!< in: space id */
- ut_stage_alter_t* stage)
+ ut_stage_alter_t* stage)
{
const ulint half = file->offset / 2;
ulint num_runs;
@@ -3442,7 +3487,7 @@ or NULL if fd, block will be used instead
ALTER TABLE. If not NULL stage->begin_phase_insert() will be called initially
and then stage->inc() will be called for each record that is processed.
@return DB_SUCCESS or error number */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_merge_insert_index_tuples(
trx_id_t trx_id,
@@ -3473,6 +3518,11 @@ row_merge_insert_index_tuples(
dtuple_t* dtuple;
ib_uint64_t inserted_rows = 0;
float curr_progress = 0;
+ dict_index_t* old_index = NULL;
+ const mrec_t* mrec = NULL;
+ ulint n_ext = 0;
+ mtr_t mtr;
+
DBUG_ENTER("row_merge_insert_index_tuples");
@@ -3525,9 +3575,6 @@ row_merge_insert_index_tuples(
for (;;) {
- const mrec_t* mrec;
- ulint n_ext;
- mtr_t mtr;
if (stage != NULL) {
stage->inc();
@@ -3563,8 +3610,7 @@ row_merge_insert_index_tuples(
mrec, index, offsets, &n_ext, tuple_heap);
}
- dict_index_t* old_index
- = dict_table_get_first_index(old_table);
+ old_index = dict_table_get_first_index(old_table);
if (dict_index_is_clust(index)
&& dict_index_is_online_ddl(old_index)) {
@@ -3604,7 +3650,6 @@ row_merge_insert_index_tuples(
}
ut_ad(dtuple_validate(dtuple));
-
error = btr_bulk->insert(dtuple);
if (error != DB_SUCCESS) {
@@ -3644,79 +3689,15 @@ row_merge_lock_table(
dict_table_t* table, /*!< in: table to lock */
enum lock_mode mode) /*!< in: LOCK_X or LOCK_S */
{
- mem_heap_t* heap;
- que_thr_t* thr;
- dberr_t err;
- sel_node_t* node;
-
ut_ad(!srv_read_only_mode);
ut_ad(mode == LOCK_X || mode == LOCK_S);
- heap = mem_heap_create(512);
-
trx->op_info = "setting table lock for creating or dropping index";
trx->ddl = true;
/* Trx for DDL should not be forced to rollback for now */
trx->in_innodb |= TRX_FORCE_ROLLBACK_DISABLE;
- node = sel_node_create(heap);
- thr = pars_complete_graph_for_exec(node, trx, heap);
- thr->graph->state = QUE_FORK_ACTIVE;
-
- /* We use the select query graph as the dummy graph needed
- in the lock module call */
-
- thr = static_cast<que_thr_t*>(
- que_fork_get_first_thr(
- static_cast<que_fork_t*>(que_node_get_parent(thr))));
-
- que_thr_move_to_run_state_for_mysql(thr, trx);
-
-run_again:
- thr->run_node = thr;
- thr->prev_node = thr->common.parent;
-
- err = lock_table(0, table, mode, thr);
-
- trx->error_state = err;
-
- if (UNIV_LIKELY(err == DB_SUCCESS)) {
- que_thr_stop_for_mysql_no_error(thr, trx);
- } else {
- que_thr_stop_for_mysql(thr);
-
- if (err != DB_QUE_THR_SUSPENDED) {
- bool was_lock_wait;
-
- was_lock_wait = row_mysql_handle_errors(
- &err, trx, thr, NULL);
-
- if (was_lock_wait) {
- goto run_again;
- }
- } else {
- que_thr_t* run_thr;
- que_node_t* parent;
-
- parent = que_node_get_parent(thr);
-
- run_thr = que_fork_start_command(
- static_cast<que_fork_t*>(parent));
-
- ut_a(run_thr == thr);
-
- /* There was a lock wait but the thread was not
- in a ready to run or running state. */
- trx->error_state = DB_LOCK_WAIT;
-
- goto run_again;
- }
- }
-
- que_graph_free(thr->graph);
- trx->op_info = "";
-
- return(err);
+ return(lock_table_for_trx(table, trx, mode));
}
/*********************************************************************//**
@@ -4090,7 +4071,8 @@ UNIV_PFS_IO defined, register the file descriptor with Performance Schema.
@param[in] path location for creating temporary merge files.
@return File descriptor */
int
-row_merge_file_create_low(void)
+row_merge_file_create_low(
+ const char* path)
{
int fd;
#ifdef UNIV_PFS_IO
@@ -4104,7 +4086,7 @@ row_merge_file_create_low(void)
"Innodb Merge Temp File",
__FILE__, __LINE__);
#endif
- fd = innobase_mysql_tmpfile();
+ fd = innobase_mysql_tmpfile(path);
#ifdef UNIV_PFS_IO
register_pfs_file_open_end(locker, fd);
#endif
@@ -4119,12 +4101,14 @@ row_merge_file_create_low(void)
/** Create a merge file in the given location.
@param[out] merge_file merge file structure
+@param[in] path location for creating temporary file
@return file descriptor, or -1 on failure */
int
row_merge_file_create(
- merge_file_t* merge_file)
+ merge_file_t* merge_file,
+ const char* path)
{
- merge_file->fd = row_merge_file_create_low();
+ merge_file->fd = row_merge_file_create_low(path);
merge_file->offset = 0;
merge_file->n_rec = 0;
@@ -4450,7 +4434,7 @@ row_merge_create_index_graph(
index->table = table;
node = ind_create_graph_create(index, heap, add_v);
- thr = pars_complete_graph_for_exec(node, trx, heap);
+ thr = pars_complete_graph_for_exec(node, trx, heap, NULL);
ut_a(thr == que_fork_start_command(
static_cast<que_fork_t*>(que_node_get_parent(thr))));
@@ -4485,6 +4469,7 @@ row_merge_create_index(
dberr_t err;
ulint n_fields = index_def->n_fields;
ulint i;
+ bool has_new_v_col = false;
DBUG_ENTER("row_merge_create_index");
@@ -4504,24 +4489,6 @@ row_merge_create_index(
for (i = 0; i < n_fields; i++) {
const char* name;
index_field_t* ifield = &index_def->fields[i];
- const char * col_name;
-
- /*
- Alter table renaming a column and then adding a index
- to this new name e.g ALTER TABLE t
- CHANGE COLUMN b c INT NOT NULL, ADD UNIQUE INDEX (c);
- requires additional check as column names are not yet
- changed when new index definitions are created. Table's
- new column names are on a array of column name pointers
- if any of the column names are changed. */
-
- if (col_names && col_names[i]) {
- col_name = col_names[i];
- } else {
- col_name = ifield->col_name ?
- dict_table_get_col_name_for_mysql(table, ifield->col_name) :
- dict_table_get_col_name(table, ifield->col_no);
- }
if (ifield->is_v_col) {
if (ifield->col_no >= table->n_v_def) {
@@ -4530,12 +4497,28 @@ row_merge_create_index(
ut_ad(ifield->col_no >= table->n_v_def);
name = add_v->v_col_name[
ifield->col_no - table->n_v_def];
+ has_new_v_col = true;
} else {
name = dict_table_get_v_col_name(
table, ifield->col_no);
}
} else {
- name = dict_table_get_col_name(table, ifield->col_no);
+ /*
+ Alter table renaming a column and then adding a index
+ to this new name e.g ALTER TABLE t
+ CHANGE COLUMN b c INT NOT NULL, ADD UNIQUE INDEX (c);
+ requires additional check as column names are not yet
+ changed when new index definitions are created. Table's
+ new column names are on a array of column name pointers
+ if any of the column names are changed. */
+
+ if (col_names && col_names[i]) {
+ name = col_names[i];
+ } else {
+ name = ifield->col_name ?
+ dict_table_get_col_name_for_mysql(table, ifield->col_name) :
+ dict_table_get_col_name(table, ifield->col_no);
+ }
}
dict_mem_index_add_field(index, name, ifield->prefix_len);
@@ -4553,6 +4536,7 @@ row_merge_create_index(
index->parser = index_def->parser;
index->is_ngram = index_def->is_ngram;
+ index->has_new_v_col = has_new_v_col;
/* Note the id of the transaction that created this
index, we use it to restrict readers from accessing
@@ -4657,6 +4641,8 @@ existing order
ALTER TABLE. stage->begin_phase_read_pk() will be called at the beginning of
this function and it will be passed to other functions for further accounting.
@param[in] add_v new virtual columns added along with indexes
+@param[in] eval_table mysql table used to evaluate virtual column
+ value, see innobase_get_computed_value().
@return DB_SUCCESS or error code */
dberr_t
row_merge_build_indexes(
@@ -4674,7 +4660,8 @@ row_merge_build_indexes(
ib_sequence_t& sequence,
bool skip_pk_sort,
ut_stage_alter_t* stage,
- const dict_add_v_col_t* add_v)
+ const dict_add_v_col_t* add_v,
+ struct TABLE* eval_table)
{
merge_file_t* merge_files;
row_merge_block_t* block;
@@ -4783,7 +4770,6 @@ row_merge_build_indexes(
total_static_cost = COST_BUILD_INDEX_STATIC * n_indexes + COST_READ_CLUSTERED_INDEX;
total_dynamic_cost = COST_BUILD_INDEX_DYNAMIC * n_indexes;
-
for (i = 0; i < n_indexes; i++) {
if (indexes[i]->type & DICT_FTS) {
ibool opt_doc_id_size = FALSE;
@@ -4842,11 +4828,11 @@ row_merge_build_indexes(
/* Read clustered index of the table and create files for
secondary index entries for merge sort */
error = row_merge_read_clustered_index(
- trx, table, old_table, new_table, online, indexes,
- fts_sort_idx, psort_info, merge_files, key_numbers,
+ trx, table, old_table, new_table, online, indexes,
+ fts_sort_idx, psort_info, merge_files, key_numbers,
n_indexes, add_cols, add_v, col_map, add_autoinc,
sequence, block, skip_pk_sort, &tmpfd, stage,
- pct_cost, crypt_data, crypt_block);
+ pct_cost, crypt_data, crypt_block, eval_table);
stage->end_phase_read_pk();
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 427d77baf28..e3a13c58794 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -43,6 +43,7 @@ Created 9/17/2000 Heikki Tuuri
#include "dict0load.h"
#include "dict0stats.h"
#include "dict0stats_bg.h"
+#include "dict0defrag_bg.h"
#include "btr0defragment.h"
#include "fil0fil.h"
#include "fil0crypt.h"
@@ -101,6 +102,8 @@ static ib_mutex_t row_drop_list_mutex;
/** Flag: has row_mysql_drop_list been initialized? */
static ibool row_mysql_drop_list_inited = FALSE;
+extern ib_mutex_t master_key_id_mutex;
+
/** Magic table names for invoking various monitor threads */
/* @{ */
static const char S_innodb_monitor[] = "innodb_monitor";
@@ -154,6 +157,21 @@ row_add_table_to_background_drop_list(
/*==================================*/
const char* name); /*!< in: table name */
+#ifdef UNIV_DEBUG
+/** Wait for the background drop list to become empty. */
+void
+row_wait_for_background_drop_list_empty()
+{
+ bool empty = false;
+ while (!empty) {
+ mutex_enter(&row_drop_list_mutex);
+ empty = (UT_LIST_GET_LEN(row_mysql_drop_list) == 0);
+ mutex_exit(&row_drop_list_mutex);
+ os_thread_sleep(100000);
+ }
+}
+#endif /* UNIV_DEBUG */
+
/*******************************************************************//**
Delays an INSERT, DELETE or UPDATE operation if the purge is lagging. */
static
@@ -763,6 +781,7 @@ handle_new_error:
case DB_CANT_CREATE_GEOMETRY_OBJECT:
case DB_TABLE_NOT_FOUND:
case DB_DECRYPTION_FAILED:
+ case DB_COMPUTE_VALUE_FAILED:
DBUG_EXECUTE_IF("row_mysql_crash_if_error", {
log_buffer_flush_to_disk();
DBUG_SUICIDE(); });
@@ -856,7 +875,8 @@ row_create_prebuilt(
uint srch_key_len = 0;
ulint search_tuple_n_fields;
- search_tuple_n_fields = 2 * dict_table_get_n_cols(table);
+ search_tuple_n_fields = 2 * (dict_table_get_n_cols(table)
+ + dict_table_get_n_v_cols(table));
clust_index = dict_table_get_first_index(table);
@@ -896,7 +916,8 @@ row_create_prebuilt(
sure if this prebuilt instance is going to be \
used in inserts */ \
+ (mysql_row_len < 256 ? mysql_row_len : 0) \
- + DTUPLE_EST_ALLOC(dict_table_get_n_cols(table)) \
+ + DTUPLE_EST_ALLOC(dict_table_get_n_cols(table) \
+ + dict_table_get_n_v_cols(table)) \
+ sizeof(que_fork_t) \
+ sizeof(que_thr_t) \
+ sizeof(*prebuilt->pcur) \
@@ -1001,6 +1022,7 @@ row_create_prebuilt(
prebuilt->blob_heap = NULL;
prebuilt->m_no_prefetch = false;
+ prebuilt->m_read_virtual_key = false;
DBUG_RETURN(prebuilt);
}
@@ -1172,7 +1194,7 @@ row_get_prebuilt_insert_row(
que_node_get_parent(
pars_complete_graph_for_exec(
node,
- prebuilt->trx, prebuilt->heap)));
+ prebuilt->trx, prebuilt->heap, prebuilt)));
prebuilt->ins_graph->state = QUE_FORK_ACTIVE;
@@ -1704,9 +1726,19 @@ row_insert_for_mysql_using_ins_graph(
} else if (srv_force_recovery) {
ib::error() << MODIFICATIONS_NOT_ALLOWED_MSG_FORCE_RECOVERY;
-
return(DB_READ_ONLY);
}
+ DBUG_EXECUTE_IF("mark_table_corrupted", {
+ /* Mark the table corrupted for the clustered index */
+ dict_index_t* index = dict_table_get_first_index(table);
+ ut_ad(dict_index_is_clust(index));
+ dict_set_corrupted(index, trx, "INSERT TABLE"); });
+
+ if (dict_table_is_corrupted(table)) {
+
+ ib::error() << "Table " << table->name << " is corrupt.";
+ return(DB_TABLE_CORRUPT);
+ }
DBUG_EXECUTE_IF("mark_table_corrupted", {
/* Mark the table corrupted for the clustered index */
@@ -1816,8 +1848,9 @@ error_exit:
doc_ids difference should not exceed
FTS_DOC_ID_MAX_STEP value. */
- if (doc_id - next_doc_id >= FTS_DOC_ID_MAX_STEP) {
- ib::error() << "Doc ID " << doc_id
+ if (next_doc_id > 1
+ && doc_id - next_doc_id >= FTS_DOC_ID_MAX_STEP) {
+ ib::error() << "Doc ID " << doc_id
<< " is too big. Its difference with"
" largest used Doc ID "
<< next_doc_id - 1 << " cannot"
@@ -1903,7 +1936,8 @@ row_prebuild_sel_graph(
que_node_get_parent(
pars_complete_graph_for_exec(
static_cast<sel_node_t*>(node),
- prebuilt->trx, prebuilt->heap)));
+ prebuilt->trx, prebuilt->heap,
+ prebuilt)));
prebuilt->sel_graph->state = QUE_FORK_ACTIVE;
}
@@ -1982,7 +2016,8 @@ row_get_prebuilt_update_vector(
que_node_get_parent(
pars_complete_graph_for_exec(
static_cast<upd_node_t*>(node),
- prebuilt->trx, prebuilt->heap)));
+ prebuilt->trx, prebuilt->heap,
+ prebuilt)));
prebuilt->upd_graph->state = QUE_FORK_ACTIVE;
}
@@ -2067,9 +2102,7 @@ init_fts_doc_id_for_ref(
foreign = *it;
- if (foreign->foreign_table == NULL) {
- break;
- }
+ ut_ad(foreign->foreign_table != NULL);
if (foreign->foreign_table->fts != NULL) {
fts_init_doc_id(foreign->foreign_table);
@@ -2365,7 +2398,13 @@ row_del_upd_for_mysql_using_cursor(
btr_pcur_copy_stored_position(node->pcur,
prebuilt->clust_pcur);
}
- row_upd_store_row(node);
+
+ ut_ad(dict_table_is_intrinsic(prebuilt->table));
+ ut_ad(!prebuilt->table->n_v_cols);
+
+ /* Internal table is created by optimiser. So there
+ should not be any virtual columns. */
+ row_upd_store_row(node, NULL, NULL);
/* Step-2: Execute DELETE operation. */
err = row_delete_for_mysql_using_cursor(node, delete_entries, false);
@@ -2632,6 +2671,7 @@ run_again:
node->cascade_upd_nodes = cascade_upd_nodes;
cascade_upd_nodes->pop_front();
thr->fk_cascade_depth++;
+ prebuilt->m_mysql_table = NULL;
goto run_again;
}
@@ -3033,8 +3073,6 @@ row_create_table_for_mysql(
tab_node_t* node;
mem_heap_t* heap;
que_thr_t* thr;
- const char* table_name;
- ulint table_name_len;
dberr_t err;
ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
@@ -3085,7 +3123,7 @@ err_exit:
node = tab_create_graph_create(table, heap, mode, key_id);
- thr = pars_complete_graph_for_exec(node, trx, heap);
+ thr = pars_complete_graph_for_exec(node, trx, heap, NULL);
ut_a(thr == que_fork_start_command(
static_cast<que_fork_t*>(que_node_get_parent(thr))));
@@ -3115,28 +3153,39 @@ err_exit:
/* We must delete the link file. */
RemoteDatafile::delete_link_file(table->name.m_name);
- } else if (compression != NULL) {
-
- ut_ad(!is_shared_tablespace(table->space));
+ } else if (compression != NULL && compression[0] != '\0') {
+#ifdef MYSQL_COMPRESSION
+ ut_ad(!dict_table_in_shared_tablespace(table));
ut_ad(Compression::validate(compression) == DB_SUCCESS);
- err = fil_set_compression(table->space, compression);
+ err = fil_set_compression(table, compression);
- /* The tablespace must be found and we have already
- done the check for the system tablespace and the
- temporary tablespace. Compression must be a valid
- and supported algorithm. */
+ switch (err) {
+ case DB_SUCCESS:
+ break;
+ case DB_NOT_FOUND:
+ case DB_UNSUPPORTED:
+ case DB_IO_NO_PUNCH_HOLE_FS:
+ /* Return these errors */
+ break;
+ case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
+ /* Page Compression will not be used. */
+ err = DB_SUCCESS;
+ break;
+ default:
+ ut_error;
+ }
- /* However, we can check for file system punch hole
- support only after creating the tablespace. On Windows
+ /* We can check for file system punch hole support
+ only after creating the tablespace. On Windows
we can query that information but not on Linux. */
-
ut_ad(err == DB_SUCCESS
- || err == DB_IO_NO_PUNCH_HOLE_FS);
-
- /* In non-strict mode we ignore dodgy compression
- settings. */
+ || err == DB_IO_NO_PUNCH_HOLE_FS);
+#endif /* MYSQL_COMPRESSION */
+
+ /* In non-strict mode we ignore dodgy compression
+ settings. */
}
}
@@ -3166,7 +3215,7 @@ err_exit:
break;
- case DB_UNSUPPORTED:
+ case DB_UNSUPPORTED:
case DB_TOO_MANY_CONCURRENT_TRXS:
/* We already have .ibd file here. it should be deleted. */
@@ -3294,10 +3343,9 @@ row_create_index_for_mysql(
in dict0crea.cc. */
heap = mem_heap_create(512);
-
node = ind_create_graph_create(index, heap, NULL);
- thr = pars_complete_graph_for_exec(node, trx, heap);
+ thr = pars_complete_graph_for_exec(node, trx, heap, NULL);
ut_a(thr == que_fork_start_command(
static_cast<que_fork_t*>(
@@ -3355,7 +3403,8 @@ row_create_index_for_mysql(
idx = dict_table_get_index_on_name(table, index_name);
ut_ad(idx);
- err = fts_create_index_tables(trx, idx);
+ err = fts_create_index_tables_low(
+ trx, idx, table->name.m_name, table->id);
}
error_handling:
@@ -3663,15 +3712,16 @@ row_add_table_to_background_drop_list(
return(TRUE);
}
-/*********************************************************************//**
-Reassigns the table identifier of a table.
+/** Reassigns the table identifier of a table.
+@param[in,out] table table
+@param[in,out] trx transaction
+@param[out] new_id new table id
@return error code or DB_SUCCESS */
dberr_t
row_mysql_table_id_reassign(
-/*========================*/
- dict_table_t* table, /*!< in/out: table */
- trx_t* trx, /*!< in/out: transaction */
- table_id_t* new_id) /*!< out: new table id */
+ dict_table_t* table,
+ trx_t* trx,
+ table_id_t* new_id)
{
dberr_t err;
pars_info_t* info = pars_info_create();
@@ -3694,6 +3744,8 @@ row_mysql_table_id_reassign(
" WHERE TABLE_ID = :old_id;\n"
"UPDATE SYS_INDEXES SET TABLE_ID = :new_id\n"
" WHERE TABLE_ID = :old_id;\n"
+ "UPDATE SYS_VIRTUAL SET TABLE_ID = :new_id\n"
+ " WHERE TABLE_ID = :old_id;\n"
"END;\n", FALSE, trx);
return(err);
@@ -3892,6 +3944,33 @@ row_discard_tablespace(
return(err);
}
+ /* For encrypted table, before we discard the tablespace,
+ we need save the encryption information into table, otherwise,
+ this information will be lost in fil_discard_tablespace along
+ with fil_space_free(). */
+ if (dict_table_is_encrypted(table)) {
+ ut_ad(table->encryption_key == NULL
+ && table->encryption_iv == NULL);
+
+ table->encryption_key =
+ static_cast<byte*>(mem_heap_alloc(table->heap,
+ ENCRYPTION_KEY_LEN));
+
+ table->encryption_iv =
+ static_cast<byte*>(mem_heap_alloc(table->heap,
+ ENCRYPTION_KEY_LEN));
+
+ fil_space_t* space = fil_space_get(table->space);
+ ut_ad(FSP_FLAGS_GET_ENCRYPTION(space->flags));
+
+ memcpy(table->encryption_key,
+ space->encryption_key,
+ ENCRYPTION_KEY_LEN);
+ memcpy(table->encryption_iv,
+ space->encryption_iv,
+ ENCRYPTION_KEY_LEN);
+ }
+
/* Discard the physical file that is used for the tablespace. */
err = fil_discard_tablespace(table->space);
@@ -4033,7 +4112,7 @@ row_mysql_lock_table(
trx->op_info = op_info;
node = sel_node_create(heap);
- thr = pars_complete_graph_for_exec(node, trx, heap);
+ thr = pars_complete_graph_for_exec(node, trx, heap, NULL);
thr->graph->state = QUE_FORK_ACTIVE;
/* We use the select query graph as the dummy graph needed
@@ -4098,7 +4177,6 @@ fil_wait_crypt_bg_threads(
{
uint start = time(0);
uint last = start;
-
if (table->space != 0) {
fil_space_crypt_mark_space_closing(table->space);
}
@@ -4115,7 +4193,6 @@ fil_wait_crypt_bg_threads(
<< table->name.m_name << " space: " << table->space;
last = now;
}
-
if (now >= start + 300) {
ib::warn()
<< "After " << now - start
@@ -4126,7 +4203,6 @@ fil_wait_crypt_bg_threads(
}
}
}
-
/** Drop ancillary FTS tables as part of dropping a table.
@param[in,out] table Table cache entry
@param[in,out] trx Transaction handle
@@ -4227,23 +4303,25 @@ This deletes the fil_space_t if found and the file on disk.
@param[in] tablename Table name, same as the tablespace name
@param[in] filepath File path of tablespace to delete
@param[in] is_temp Is this a temporary table/tablespace
+@param[in] is_encrypted Is this an encrypted table/tablespace
@param[in] trx Transaction handle
@return error code or DB_SUCCESS */
UNIV_INLINE
dberr_t
row_drop_single_table_tablespace(
- ulint space_id,
+ ulint space_id,
const char* tablename,
const char* filepath,
- bool is_temp,
- trx_t* trx)
+ bool is_temp,
+ bool is_encrypted,
+ trx_t* trx)
{
dberr_t err = DB_SUCCESS;
/* This might be a temporary single-table tablespace if the table
is compressed and temporary. If so, don't spam the log when we
delete one of these or if we can't find the tablespace. */
- bool print_msg = !is_temp;
+ bool print_msg = !is_temp && !is_encrypted;
/* If the tablespace is not in the cache, just delete the file. */
if (!fil_space_for_table_exists_in_mem(
@@ -4256,7 +4334,6 @@ row_drop_single_table_tablespace(
ib::info() << "Removed datafile " << filepath
<< " for table " << tablename;
}
-
} else if (fil_delete_tablespace(space_id, BUF_REMOVE_FLUSH_NO_WRITE)
!= DB_SUCCESS) {
@@ -4347,7 +4424,6 @@ row_drop_table_for_mysql(
err = DB_TABLE_NOT_FOUND;
goto funct_exit;
}
-
/* If table is encrypted and table page encryption failed
return error. */
if (table->is_encrypted) {
@@ -4370,6 +4446,7 @@ row_drop_table_for_mysql(
trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
}
}
+
/* Turn on this drop bit before we could release the dictionary
latch */
table->to_be_dropped = true;
@@ -4744,6 +4821,7 @@ row_drop_table_for_mysql(
switch (err) {
ulint space_id;
bool is_temp;
+ bool is_encrypted;
bool ibd_file_missing;
bool is_discarded;
bool shared_tablespace;
@@ -4753,6 +4831,7 @@ row_drop_table_for_mysql(
ibd_file_missing = table->ibd_file_missing;
is_discarded = dict_table_is_discarded(table);
is_temp = dict_table_is_temporary(table);
+ is_encrypted = dict_table_is_encrypted(table);
shared_tablespace = DICT_TF_HAS_SHARED_SPACE(table->flags);
/* If there is a temp path then the temp flag is set.
@@ -4775,7 +4854,6 @@ row_drop_table_for_mysql(
dict_table_t. Free this memory before returning. */
if (DICT_TF_HAS_DATA_DIR(table->flags)) {
ut_a(table->data_dir_path);
-
filepath = fil_make_filepath(
table->data_dir_path,
table->name.m_name, IBD, true);
@@ -4798,12 +4876,32 @@ row_drop_table_for_mysql(
nor system or shared general tablespaces. */
if (is_discarded || ibd_file_missing || shared_tablespace
|| is_system_tablespace(space_id)) {
- break;
+ /* For encrypted table, if ibd file can not be decrypt,
+ we also set ibd_file_missing. We still need to try to
+ remove the ibd file for this. */
+ if (is_discarded || !is_encrypted
+ || !ibd_file_missing) {
+ break;
+ }
}
+#ifdef MYSQL_ENCRYPTION
+ if (is_encrypted) {
+ /* Require the mutex to block key rotation. */
+ mutex_enter(&master_key_id_mutex);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
/* We can now drop the single-table tablespace. */
err = row_drop_single_table_tablespace(
- space_id, tablename, filepath, is_temp, trx);
+ space_id, tablename, filepath,
+ is_temp, is_encrypted, trx);
+
+#ifdef MYSQL_ENCRYPTION
+ if (is_encrypted) {
+ mutex_exit(&master_key_id_mutex);
+ }
+#endif /* MYSQL_ENCRYPTION */
break;
case DB_OUT_OF_FILE_SPACE:
@@ -4866,9 +4964,7 @@ funct_exit:
mem_heap_free(heap);
}
- if (filepath) {
- ut_free(filepath);
- }
+ ut_free(filepath);
if (locked_dictionary) {
@@ -5202,7 +5298,7 @@ loop:
Checks if a table name contains the string "/#sql" which denotes temporary
tables in MySQL.
@return true if temporary table */
-UNIV_INTERN MY_ATTRIBUTE((warn_unused_result))
+MY_ATTRIBUTE((warn_unused_result))
bool
row_is_mysql_tmp_table_name(
/*========================*/
@@ -5648,6 +5744,15 @@ end:
goto funct_exit;
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ /* In case of copy alter, template db_name and
+ table_name should be renamed only for newly
+ created table. */
+ if (table->vc_templ != NULL && !new_is_tmp) {
+ innobase_rename_vc_templ(table);
+ }
+#endif
+
/* We only want to switch off some of the type checking in
an ALTER TABLE...ALGORITHM=COPY, not in a RENAME. */
dict_names_t fk_tables;
@@ -5681,6 +5786,24 @@ end:
trx->error_state = DB_SUCCESS;
}
+ /* Check whether virtual column or stored column affects
+ the foreign key constraint of the table. */
+ if (dict_foreigns_has_s_base_col(
+ table->foreign_set, table)) {
+ err = DB_NO_FK_ON_S_BASE_COL;
+ ut_a(DB_SUCCESS == dict_table_rename_in_cache(
+ table, old_name, FALSE));
+ trx->error_state = DB_SUCCESS;
+ trx_rollback_to_savepoint(trx, NULL);
+ trx->error_state = DB_SUCCESS;
+ goto funct_exit;
+ }
+
+ /* Fill the virtual column set in foreign when
+ the table undergoes copy alter operation. */
+ dict_mem_table_free_foreign_vcol_set(table);
+ dict_mem_table_fill_foreign_vcol_set(table);
+
while (!fk_tables.empty()) {
dict_load_table(fk_tables.front(), true,
DICT_ERR_IGNORE_NONE);
@@ -5906,7 +6029,6 @@ func_exit:
cmp = cmp_dtuple_rec_with_match(prev_entry, rec, offsets,
&matched_fields);
-
contains_null = FALSE;
/* In a unique secondary index we allow equal key values if
@@ -5978,7 +6100,6 @@ next_rec:
goto loop;
}
-
/*********************************************************************//**
Determines if a table is a magic monitor table.
@return true if monitor table */
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index 6282fd9d4ec..bac55694056 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -504,10 +504,18 @@ row_purge_remove_sec_if_poss_leaf(
if (dict_index_is_spatial(index)) {
const page_t* page;
+ const trx_t* trx = NULL;
+
+ if (btr_cur->rtr_info != NULL
+ && btr_cur->rtr_info->thr != NULL) {
+ trx = thr_get_trx(
+ btr_cur->rtr_info->thr);
+ }
page = btr_cur_get_page(btr_cur);
if (!lock_test_prdt_page_lock(
+ trx,
page_get_space_id(page),
page_get_page_no(page))
&& page_get_n_recs(page) < 2
@@ -598,6 +606,25 @@ retry:
ut_a(success);
}
+/** Skip uncommitted virtual indexes on newly added virtual column.
+@param[in,out] index dict index object */
+static
+inline
+void
+row_purge_skip_uncommitted_virtual_index(
+ dict_index_t*& index)
+{
+ /* We need to skip virtual indexes which is not
+ committed yet. It's safe because these indexes are
+ newly created by alter table, and because we do
+ not support LOCK=NONE when adding an index on newly
+ added virtual column.*/
+ while (index != NULL && dict_index_has_virtual(index)
+ && !index->is_committed() && index->has_new_v_col) {
+ index = dict_table_get_next_index(index);
+ }
+}
+
/***********************************************************//**
Purges a delete marking of a record.
@retval true if the row was not found, or it was successfully removed
@@ -617,6 +644,8 @@ row_purge_del_mark(
/* skip corrupted secondary index */
dict_table_skip_corrupt_index(node->index);
+ row_purge_skip_uncommitted_virtual_index(node->index);
+
if (!node->index) {
break;
}
@@ -665,6 +694,8 @@ row_purge_upd_exist_or_extern_func(
while (node->index != NULL) {
dict_table_skip_corrupt_index(node->index);
+ row_purge_skip_uncommitted_virtual_index(node->index);
+
if (!node->index) {
break;
}
@@ -837,6 +868,7 @@ try_again:
goto err_exit;
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
if (node->table->n_v_cols && !node->table->vc_templ
&& dict_table_has_indexed_v_cols(node->table)) {
/* Need server fully up for virtual column computation */
@@ -854,6 +886,7 @@ try_again:
/* Initialize the template for the table */
innobase_init_vc_templ(node->table);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/* Disable purging for temp-tables as they are short-lived
and no point in re-organzing such short lived tables */
diff --git a/storage/innobase/row/row0quiesce.cc b/storage/innobase/row/row0quiesce.cc
index 92b78fabde2..58f1477efb6 100644
--- a/storage/innobase/row/row0quiesce.cc
+++ b/storage/innobase/row/row0quiesce.cc
@@ -36,6 +36,10 @@ Created 2012-02-08 by Sunny Bains.
#include "trx0purge.h"
#include "fsp0sysspace.h"
+#ifdef HAVE_MY_AES_H
+#include <my_aes.h>
+#endif
+
/*********************************************************************//**
Write the meta data (index user fields) config file.
@return DB_SUCCESS or error code. */
@@ -476,6 +480,210 @@ row_quiesce_write_cfg(
return(err);
}
+#ifdef MYSQL_ENCRYPTION
+
+/** Write the transfer key to CFP file.
+@param[in] table write the data for this table
+@param[in] file file to write to
+@param[in] thd session
+@return DB_SUCCESS or error code. */
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
+dberr_t
+row_quiesce_write_transfer_key(
+ const dict_table_t* table,
+ FILE* file,
+ THD* thd)
+{
+ byte key_size[sizeof(ib_uint32_t)];
+ byte row[ENCRYPTION_KEY_LEN * 3];
+ byte* ptr = row;
+ byte* transfer_key = ptr;
+ lint elen;
+
+ ut_ad(table->encryption_key != NULL
+ && table->encryption_iv != NULL);
+
+ /* Write the encryption key size. */
+ mach_write_to_4(key_size, ENCRYPTION_KEY_LEN);
+
+ if (fwrite(&key_size, 1, sizeof(key_size), file)
+ != sizeof(key_size)) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while writing key size.");
+
+ return(DB_IO_ERROR);
+ }
+
+ /* Generate and write the transfer key. */
+ Encryption::random_value(transfer_key);
+ if (fwrite(transfer_key, 1, ENCRYPTION_KEY_LEN, file)
+ != ENCRYPTION_KEY_LEN) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while writing transfer key.");
+
+ return(DB_IO_ERROR);
+ }
+
+ ptr += ENCRYPTION_KEY_LEN;
+
+ /* Encrypt tablespace key. */
+ elen = my_aes_encrypt(
+ reinterpret_cast<unsigned char*>(table->encryption_key),
+ ENCRYPTION_KEY_LEN,
+ ptr,
+ reinterpret_cast<unsigned char*>(transfer_key),
+ ENCRYPTION_KEY_LEN,
+ my_aes_256_ecb,
+ NULL, false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while encrypt tablespace key.");
+ return(DB_ERROR);
+ }
+
+ /* Write encrypted tablespace key */
+ if (fwrite(ptr, 1, ENCRYPTION_KEY_LEN, file)
+ != ENCRYPTION_KEY_LEN) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while writing encrypted tablespace key.");
+
+ return(DB_IO_ERROR);
+ }
+ ptr += ENCRYPTION_KEY_LEN;
+
+ /* Encrypt tablespace iv. */
+ elen = my_aes_encrypt(
+ reinterpret_cast<unsigned char*>(table->encryption_iv),
+ ENCRYPTION_KEY_LEN,
+ ptr,
+ reinterpret_cast<unsigned char*>(transfer_key),
+ ENCRYPTION_KEY_LEN,
+ my_aes_256_ecb,
+ NULL, false);
+
+ if (elen == MY_AES_BAD_DATA) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while encrypt tablespace iv.");
+ return(DB_ERROR);
+ }
+
+ /* Write encrypted tablespace iv */
+ if (fwrite(ptr, 1, ENCRYPTION_KEY_LEN, file)
+ != ENCRYPTION_KEY_LEN) {
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno),
+ "while writing encrypted tablespace iv.");
+
+ return(DB_IO_ERROR);
+ }
+
+ return(DB_SUCCESS);
+}
+
+/** Write the encryption data after quiesce.
+@param[in] table write the data for this table
+@param[in] thd session
+@return DB_SUCCESS or error code */
+static MY_ATTRIBUTE((nonnull, warn_unused_result))
+dberr_t
+row_quiesce_write_cfp(
+ dict_table_t* table,
+ THD* thd)
+{
+ dberr_t err;
+ char name[OS_FILE_MAX_PATH];
+
+ /* If table is not encrypted, return. */
+ if (!dict_table_is_encrypted(table)) {
+ return(DB_SUCCESS);
+ }
+
+ /* Get the encryption key and iv from space */
+ /* For encrypted table, before we discard the tablespace,
+ we need save the encryption information into table, otherwise,
+ this information will be lost in fil_discard_tablespace along
+ with fil_space_free(). */
+ if (table->encryption_key == NULL) {
+ table->encryption_key =
+ static_cast<byte*>(mem_heap_alloc(table->heap,
+ ENCRYPTION_KEY_LEN));
+
+ table->encryption_iv =
+ static_cast<byte*>(mem_heap_alloc(table->heap,
+ ENCRYPTION_KEY_LEN));
+
+ fil_space_t* space = fil_space_get(table->space);
+ ut_ad(space != NULL && FSP_FLAGS_GET_ENCRYPTION(space->flags));
+
+ memcpy(table->encryption_key,
+ space->encryption_key,
+ ENCRYPTION_KEY_LEN);
+ memcpy(table->encryption_iv,
+ space->encryption_iv,
+ ENCRYPTION_KEY_LEN);
+ }
+
+ srv_get_encryption_data_filename(table, name, sizeof(name));
+
+ ib::info() << "Writing table encryption data to '" << name << "'";
+
+ FILE* file = fopen(name, "w+b");
+
+ if (file == NULL) {
+ ib_errf(thd, IB_LOG_LEVEL_WARN, ER_CANT_CREATE_FILE,
+ name, errno, strerror(errno));
+
+ err = DB_IO_ERROR;
+ } else {
+ err = row_quiesce_write_transfer_key(table, file, thd);
+
+ if (fflush(file) != 0) {
+
+ char msg[BUFSIZ];
+
+ ut_snprintf(msg, sizeof(msg), "%s flush() failed",
+ name);
+
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno), msg);
+
+ err = DB_IO_ERROR;
+ }
+
+ if (fclose(file) != 0) {
+ char msg[BUFSIZ];
+
+ ut_snprintf(msg, sizeof(msg), "%s flose() failed",
+ name);
+
+ ib_senderrf(
+ thd, IB_LOG_LEVEL_WARN, ER_IO_WRITE_ERROR,
+ errno, strerror(errno), msg);
+ err = DB_IO_ERROR;
+ }
+ }
+
+ /* Clean the encryption information */
+ table->encryption_key = NULL;
+ table->encryption_iv = NULL;
+
+ return(err);
+}
+#endif /* MYSQL_ENCRYPTION */
+
/*********************************************************************//**
Check whether a table has an FTS index defined on it.
@return true if an FTS index exists on the table */
@@ -518,6 +726,7 @@ row_quiesce_table_start(
ut_a(trx->mysql_thd != 0);
+ ut_ad(fil_space_get(table->space) != NULL);
ib::info() << "Sync to disk of " << table->name << " started.";
if (trx_purge_state() != PURGE_STATE_DISABLED) {
@@ -525,7 +734,7 @@ row_quiesce_table_start(
}
for (ulint count = 0;
- ibuf_merge_in_background(true, table->space) != 0
+ ibuf_merge_space(table->space) != 0
&& !trx_is_interrupted(trx);
++count) {
if (!(count % 20)) {
@@ -535,9 +744,24 @@ row_quiesce_table_start(
}
if (!trx_is_interrupted(trx)) {
+ extern ib_mutex_t master_key_id_mutex;
+
+#ifdef MYSQL_ENCRYPTION
+ if (dict_table_is_encrypted(table)) {
+ /* Require the mutex to block key rotation. */
+ mutex_enter(&master_key_id_mutex);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
buf_LRU_flush_or_remove_pages(
table->space, BUF_REMOVE_FLUSH_WRITE, trx);
+#ifdef MYSQL_ENCRYPTION
+ if (dict_table_is_encrypted(table)) {
+ mutex_exit(&master_key_id_mutex);
+ }
+#endif /* MYSQL_ENCRYPTION */
+
if (trx_is_interrupted(trx)) {
ib::warn() << "Quiesce aborted!";
@@ -547,6 +771,12 @@ row_quiesce_table_start(
ib::warn() << "There was an error writing to the"
" meta data file";
+#ifdef MYSQL_ENCRYPTION
+ } else if (row_quiesce_write_cfp(table, trx->mysql_thd)
+ != DB_SUCCESS) {
+ ib::warn() << "There was an error writing to the"
+ " encryption info file";
+#endif /* MYSQL_ENCRYPTION */
} else {
ib::info() << "Table " << table->name
<< " flushed to disk";
@@ -599,6 +829,19 @@ row_quiesce_table_complete(
ib::info() << "Deleting the meta-data file '" << cfg_name << "'";
+ if (dict_table_is_encrypted(table)) {
+ char cfp_name[OS_FILE_MAX_PATH];
+
+ srv_get_encryption_data_filename(table,
+ cfp_name,
+ sizeof(cfp_name));
+
+ os_file_delete_if_exists(innodb_data_file_key, cfp_name, NULL);
+
+ ib::info() << "Deleting the meta-data file '"
+ << cfp_name << "'";
+ }
+
if (trx_purge_state() != PURGE_STATE_DISABLED) {
trx_purge_run();
}
diff --git a/storage/innobase/row/row0row.cc b/storage/innobase/row/row0row.cc
index da7039581cf..5c71e6e98bc 100644
--- a/storage/innobase/row/row0row.cc
+++ b/storage/innobase/row/row0row.cc
@@ -155,10 +155,6 @@ row_build_index_entry_low(
which is for store MBR. */
if (dict_index_is_spatial(index) && i == 0) {
double* mbr;
- col_spatial_status spatial_status;
-
- spatial_status = dict_col_get_spatial_status(col);
- ut_ad(spatial_status != SPATIAL_NONE);
dfield_copy(dfield, dfield2);
dfield->type.prtype |= DATA_GIS_MBR;
@@ -181,6 +177,11 @@ row_build_index_entry_low(
if (flag == ROW_BUILD_FOR_PURGE) {
byte* ptr = NULL;
+ spatial_status_t spatial_status;
+ spatial_status =
+ dfield_get_spatial_status(
+ dfield2);
+
switch (spatial_status) {
case SPATIAL_ONLY:
ptr = static_cast<byte*>(
@@ -199,6 +200,11 @@ row_build_index_entry_low(
break;
case SPATIAL_NONE:
+ /* Undo record is logged before
+ spatial index is created.*/
+ return(NULL);
+
+ case SPATIAL_UNKNOWN:
ut_ad(0);
}
@@ -1137,7 +1143,7 @@ row_raw_format_int(
ret = ut_snprintf(
buf, buf_size,
- unsigned_type ? UINT32PF : "%f", unsigned_type ? value : (double)value) + 1;
+ unsigned_type ? "%llu" : "%lld", (longlong) value)+1;
} else {
*format_in_hex = TRUE;
diff --git a/storage/innobase/row/row0sel.cc b/storage/innobase/row/row0sel.cc
index 292ea1d91ca..9a94eb99cd3 100644
--- a/storage/innobase/row/row0sel.cc
+++ b/storage/innobase/row/row0sel.cc
@@ -148,26 +148,28 @@ row_sel_sec_rec_is_for_blob(
return(!cmp_data_data(mtype, prtype, buf, len, sec_field, sec_len));
}
-/********************************************************************//**
-Returns TRUE if the user-defined column values in a secondary index record
+/** Returns TRUE if the user-defined column values in a secondary index record
are alphabetically the same as the corresponding columns in the clustered
index record.
NOTE: the comparison is NOT done as a binary comparison, but character
fields are compared with collation!
+@param[in] sec_rec secondary index record
+@param[in] sec_index secondary index
+@param[in] clust_rec clustered index record;
+ must be protected by a page s-latch
+@param[in] clust_index clustered index
+@param[in] thr query thread
@return TRUE if the secondary record is equal to the corresponding
fields in the clustered record, when compared with collation;
FALSE if not equal or if the clustered record has been marked for deletion */
static
ibool
row_sel_sec_rec_is_for_clust_rec(
-/*=============================*/
- const rec_t* sec_rec, /*!< in: secondary index record */
- dict_index_t* sec_index, /*!< in: secondary index */
- const rec_t* clust_rec, /*!< in: clustered index record;
- must be protected by a lock or
- a page latch against deletion
- in rollback or purge */
- dict_index_t* clust_index) /*!< in: clustered index */
+ const rec_t* sec_rec,
+ dict_index_t* sec_index,
+ const rec_t* clust_rec,
+ dict_index_t* clust_index,
+ que_thr_t* thr)
{
const byte* sec_field;
ulint sec_len;
@@ -210,7 +212,6 @@ row_sel_sec_rec_is_for_clust_rec(
ulint clust_len;
ulint len;
bool is_virtual;
- row_ext_t* ext;
ifield = dict_index_get_nth_field(sec_index, i);
col = dict_field_get_col(ifield);
@@ -220,9 +221,11 @@ row_sel_sec_rec_is_for_clust_rec(
/* For virtual column, its value will need to be
reconstructed from base column in cluster index */
if (is_virtual) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
const dict_v_col_t* v_col;
const dtuple_t* row;
dfield_t* vfield;
+ row_ext_t* ext;
v_col = reinterpret_cast<const dict_v_col_t*>(col);
@@ -233,11 +236,14 @@ row_sel_sec_rec_is_for_clust_rec(
vfield = innobase_get_computed_value(
row, v_col, clust_index,
- NULL, &heap, NULL, NULL, false);
+ &heap, NULL, NULL,
+ thr_get_trx(thr)->mysql_thd,
+ thr->prebuilt->m_mysql_table, NULL,
+ NULL, NULL);
clust_len = vfield->len;
clust_field = static_cast<byte*>(vfield->data);
-
+#endif /* MYSQL_VIRTUAL_COLUMNS */
} else {
clust_pos = dict_col_get_clust_pos(col, clust_index);
@@ -1018,7 +1024,8 @@ row_sel_get_clust_rec(
|| rec_get_deleted_flag(rec, dict_table_is_comp(
plan->table)))
&& !row_sel_sec_rec_is_for_clust_rec(rec, plan->index,
- clust_rec, index)) {
+ clust_rec, index,
+ thr)) {
goto func_exit;
}
}
@@ -1519,7 +1526,7 @@ row_sel_try_search_shortcut(
}
} else if (!srv_read_only_mode
&& !lock_sec_rec_cons_read_sees(
- rec, index, offsets, node->read_view)) {
+ rec, index, node->read_view)) {
ret = SEL_RETRY;
goto func_exit;
@@ -1563,7 +1570,7 @@ func_exit:
/*********************************************************************//**
Performs a select step.
@return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_sel(
/*====*/
@@ -1966,7 +1973,7 @@ skip_lock:
}
} else if (!srv_read_only_mode
&& !lock_sec_rec_cons_read_sees(
- rec, index, offsets, node->read_view)) {
+ rec, index, node->read_view)) {
cons_read_requires_clust_rec = TRUE;
}
@@ -3227,9 +3234,10 @@ row_sel_store_mysql_rec(
if (templ->is_virtual && dict_index_is_clust(index)) {
/* Skip virtual columns if it is not a covered
- search */
+ search or virtual key read is not requested. */
if (!dict_index_has_virtual(prebuilt->index)
- || !prebuilt->read_just_key
+ || (!prebuilt->read_just_key
+ && !prebuilt->m_read_virtual_key)
|| !rec_clust) {
continue;
}
@@ -3243,6 +3251,24 @@ row_sel_store_mysql_rec(
const dfield_t* dfield = dtuple_get_nth_v_field(
vrow, col->v_pos);
+ /* If this is a partitioned table, it might request
+ InnoDB to fill out virtual column data for serach
+ index key values while other non key columns are also
+ getting selected. The non-key virtual columns may
+ not be materialized and we should skip them. */
+ if (dfield_get_type(dfield)->mtype == DATA_MISSING) {
+ ulint prefix;
+ ut_ad(prebuilt->m_read_virtual_key);
+
+ /* If it is part of index key the data should
+ have been materialized. */
+ ut_ad(dict_index_get_nth_col_or_prefix_pos(
+ prebuilt->index, col->v_pos, false,
+ true, &prefix) == ULINT_UNDEFINED);
+
+ continue;
+ }
+
if (dfield->len == UNIV_SQL_NULL) {
mysql_rec[templ->mysql_null_byte_offset]
|= (byte) templ->mysql_null_bit_mask;
@@ -3283,6 +3309,7 @@ row_sel_store_mysql_rec(
if (!row_sel_store_mysql_field(mysql_rec, prebuilt,
rec, index, offsets,
field_no, templ)) {
+
DBUG_RETURN(FALSE);
}
}
@@ -3580,7 +3607,7 @@ row_sel_get_clust_rec_for_mysql(
|| rec_get_deleted_flag(rec, dict_table_is_comp(
sec_index->table)))
&& !row_sel_sec_rec_is_for_clust_rec(
- rec, sec_index, clust_rec, clust_index)) {
+ rec, sec_index, clust_rec, clust_index, thr)) {
clust_rec = NULL;
}
@@ -4404,6 +4431,9 @@ row_sel_fill_vrow(
*vrow = dtuple_create_with_vcol(
heap, 0, dict_table_get_n_v_cols(index->table));
+ /* Initialize all virtual row's mtype to DATA_MISSING */
+ dtuple_init_v_fld(*vrow);
+
for (ulint i = 0; i < dict_index_get_n_fields(index); i++) {
const dict_field_t* field;
const dict_col_t* col;
@@ -4423,6 +4453,7 @@ row_sel_fill_vrow(
dfield_t* dfield = dtuple_get_nth_v_field(
*vrow, vcol->v_pos);
dfield_set_data(dfield, data, len);
+ dict_col_copy_type(col, dfield_get_type(dfield));
}
}
}
@@ -4522,7 +4553,6 @@ row_search_mvcc(
return(DB_DECRYPTION_FAILED);
} else if (!prebuilt->index_usable) {
-
DBUG_RETURN(DB_MISSING_HISTORY);
} else if (dict_index_is_corrupted(prebuilt->index)) {
@@ -4530,10 +4560,12 @@ row_search_mvcc(
DBUG_RETURN(DB_CORRUPTION);
}
- /* We need to get the virtual row value only if this is covered
- index scan */
+ /* We need to get the virtual column values stored in secondary
+ index key, if this is covered index scan or virtual key read is
+ requested. */
bool need_vrow = dict_index_has_virtual(prebuilt->index)
- && prebuilt->read_just_key;
+ && (prebuilt->read_just_key
+ || prebuilt->m_read_virtual_key);
/*-------------------------------------------------------------*/
/* PHASE 0: Release a possible s-latch we are holding on the
@@ -5462,7 +5494,7 @@ no_gap_lock:
if (!srv_read_only_mode
&& !lock_sec_rec_cons_read_sees(
- rec, index, offsets, trx->read_view)) {
+ rec, index, trx->read_view)) {
/* We should look at the clustered index.
However, as this is a non-locking read,
we can skip the clustered index lookup if
diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc
index ff70e0ff31e..25dc274b0c5 100644
--- a/storage/innobase/row/row0trunc.cc
+++ b/storage/innobase/row/row0trunc.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2013, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -548,6 +548,7 @@ private:
/** Truncate log file name. */
char* m_log_file_name;
+
public:
/** Magic Number to indicate truncate action is complete. */
const static ib_uint32_t s_magic;
@@ -1217,7 +1218,7 @@ Finish the TRUNCATE operations for both commit and rollback.
@param err status of truncate operation
@return DB_SUCCESS or error code */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_complete(
dict_table_t* table,
@@ -1301,7 +1302,7 @@ Handle FTS truncate issues.
@param new_id new id for the table
@param trx transaction covering the truncate
@return DB_SUCCESS or error code. */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_fts(
dict_table_t* table,
@@ -1386,7 +1387,7 @@ Update system table to reflect new table id.
dict_sys->mutex around call to pars_sql.
@param trx transaction
@return error code or DB_SUCCESS */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_update_table_id(
table_id_t old_table_id,
@@ -1426,7 +1427,7 @@ row_truncate_update_table_id(
Get the table id to truncate.
@param truncate_t old/new table id of table to truncate
@return table_id_t table_id to use in SYS_XXXX table update. */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
table_id_t
row_truncate_get_trunc_table_id(
const truncate_t& truncate)
@@ -1448,7 +1449,7 @@ Update system table to reflect new table id and root page number.
dict_sys->mutex around call to pars_sql.
@param mark_index_corrupted if true, then mark index corrupted.
@return error code or DB_SUCCESS */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_update_sys_tables_during_fix_up(
const truncate_t& truncate,
@@ -1479,10 +1480,42 @@ row_truncate_update_sys_tables_during_fix_up(
table_id, new_table_id, reserve_dict_mutex, trx);
if (err == DB_SUCCESS) {
- trx_commit_for_mysql(trx);
- trx_free_for_background(trx);
+ dict_mutex_enter_for_mysql();
+
+ /* Remove the table with old table_id from cache. */
+ dict_table_t* old_table = dict_table_open_on_id(
+ table_id, true, DICT_TABLE_OP_NORMAL);
+
+ if (old_table != NULL) {
+ dict_table_close(old_table, true, false);
+ dict_table_remove_from_cache(old_table);
+ }
+
+ /* Open table with new table_id and set table as
+ corrupted if it has FTS index. */
+
+ dict_table_t* table = dict_table_open_on_id(
+ new_table_id, true, DICT_TABLE_OP_NORMAL);
+ ut_ad(table->id == new_table_id);
+
+ bool has_internal_doc_id =
+ dict_table_has_fts_index(table)
+ || DICT_TF2_FLAG_IS_SET(
+ table, DICT_TF2_FTS_HAS_DOC_ID);
+
+ if (has_internal_doc_id) {
+ trx->dict_operation_lock_mode = RW_X_LATCH;
+ fts_check_corrupt(table, trx);
+ trx->dict_operation_lock_mode = 0;
+ }
+
+ dict_table_close(table, true, false);
+ dict_mutex_exit_for_mysql();
}
+ trx_commit_for_mysql(trx);
+ trx_free_for_background(trx);
+
return(err);
}
@@ -1495,7 +1528,7 @@ SYSTEM TABLES with the new id.
@param no_redo if true, turn-off redo logging
@param trx transaction handle
@return error code or DB_SUCCESS */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_update_system_tables(
dict_table_t* table,
@@ -1564,7 +1597,7 @@ be locked in X mode.
@param table table to truncate
@param flags tablespace flags
@return error code or DB_SUCCESS */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_prepare(dict_table_t* table, ulint* flags)
{
@@ -1596,7 +1629,7 @@ Do foreign key checks before starting TRUNCATE.
@param table table being truncated
@param trx transaction covering the truncate
@return DB_SUCCESS or error code */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_foreign_key_checks(
const dict_table_t* table,
@@ -1660,7 +1693,7 @@ row_truncate_foreign_key_checks(
Do some sanity checks before starting the actual TRUNCATE.
@param table table being truncated
@return DB_SUCCESS or error code */
-static __attribute__((warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_truncate_sanity_checks(
const dict_table_t* table)
@@ -1890,7 +1923,7 @@ row_truncate_table_for_mysql(
we need to use index locks to sync up */
dict_table_x_lock_indexes(table);
- if (!dict_table_is_temporary(table) && !has_internal_doc_id) {
+ if (!dict_table_is_temporary(table)) {
if (is_file_per_table) {
@@ -2212,6 +2245,7 @@ truncate_t::fixup_tables_in_non_system_tablespace()
FIL_IBD_FILE_INITIAL_SIZE,
(*it)->m_encryption,
(*it)->m_key_id);
+
if (err != DB_SUCCESS) {
/* If checkpoint is not yet done
and table is dropped and then we might
@@ -2589,7 +2623,9 @@ truncate_t::parse(
index.m_trx_id_pos = mach_read_from_4(start_ptr);
start_ptr += 4;
- m_indexes.push_back(index);
+ if (!(index.m_type & DICT_FTS)) {
+ m_indexes.push_back(index);
+ }
}
ut_ad(!m_indexes.empty());
diff --git a/storage/innobase/row/row0uins.cc b/storage/innobase/row/row0uins.cc
index ce5e02908b2..27be7c1600e 100644
--- a/storage/innobase/row/row0uins.cc
+++ b/storage/innobase/row/row0uins.cc
@@ -220,9 +220,9 @@ row_undo_ins_remove_sec_low(
if (dict_index_is_spatial(index)) {
if (mode & BTR_MODIFY_LEAF) {
- btr_pcur_get_btr_cur(&pcur)->thr = thr;
mode |= BTR_RTREE_DELETE_MARK;
}
+ btr_pcur_get_btr_cur(&pcur)->thr = thr;
mode |= BTR_RTREE_UNDO_INS;
}
diff --git a/storage/innobase/row/row0umod.cc b/storage/innobase/row/row0umod.cc
index 2398412dcbe..81c86f8b6f7 100644
--- a/storage/innobase/row/row0umod.cc
+++ b/storage/innobase/row/row0umod.cc
@@ -213,36 +213,6 @@ row_undo_mod_remove_clust_low(
return(DB_SUCCESS);
}
- trx_id_offset = btr_cur_get_index(btr_cur)->trx_id_offset;
-
- if (!trx_id_offset) {
- mem_heap_t* heap = NULL;
- ulint trx_id_col;
- const ulint* offsets;
- ulint len;
-
- trx_id_col = dict_index_get_sys_col_pos(
- btr_cur_get_index(btr_cur), DATA_TRX_ID);
- ut_ad(trx_id_col > 0);
- ut_ad(trx_id_col != ULINT_UNDEFINED);
-
- offsets = rec_get_offsets(
- btr_cur_get_rec(btr_cur), btr_cur_get_index(btr_cur),
- NULL, trx_id_col + 1, &heap);
-
- trx_id_offset = rec_get_nth_field_offs(
- offsets, trx_id_col, &len);
- ut_ad(len == DATA_TRX_ID_LEN);
- mem_heap_free(heap);
- }
-
- if (trx_read_trx_id(btr_cur_get_rec(btr_cur) + trx_id_offset)
- != node->new_trx_id) {
- /* The record must have been purged and then replaced
- with a different one. */
- return(DB_SUCCESS);
- }
-
/* We are about to remove an old, delete-marked version of the
record that may have been delete-marked by a different transaction
than the rolling-back one. */
diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc
index cfd4f8e1b51..f72e8aa14ea 100644
--- a/storage/innobase/row/row0undo.cc
+++ b/storage/innobase/row/row0undo.cc
@@ -257,7 +257,7 @@ Fetches an undo log record and does the undo for the recorded operation.
If none left, or a partial rollback completed, returns control to the
parent node, which is always a query thread node.
@return DB_SUCCESS if operation successfully completed, else error code */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
row_undo(
/*=====*/
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 0c26325ad21..108e3d5db79 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -33,6 +33,7 @@ Created 12/27/1996 Heikki Tuuri
#endif
#include "dict0dict.h"
+#include "dict0mem.h"
#include "trx0undo.h"
#include "rem0rec.h"
#ifndef UNIV_HOTBACKUP
@@ -61,6 +62,10 @@ Created 12/27/1996 Heikki Tuuri
#include <mysql/plugin.h>
#include <mysql/service_wsrep.h>
+#ifdef WITH_WSREP
+extern my_bool wsrep_debug;
+#endif
+
/* What kind of latch and lock can we assume when the control comes to
-------------------------------------------------------------------
an update node?
@@ -179,12 +184,10 @@ wsrep_row_upd_index_is_foreign(
trx_t* trx) /*!< in: transaction */
{
dict_table_t* table = index->table;
- dict_foreign_t* foreign;
ibool froze_data_dict = FALSE;
ibool is_referenced = FALSE;
if (table->foreign_set.empty()) {
-
return(FALSE);
}
@@ -193,21 +196,13 @@ wsrep_row_upd_index_is_foreign(
froze_data_dict = TRUE;
}
- for (dict_foreign_set::iterator it= table->foreign_set.begin();
- it != table->foreign_set.end();
- ++ it)
- {
- foreign= *it;
-
- if (foreign->foreign_index == index) {
+ dict_foreign_set::iterator it
+ = std::find_if(table->foreign_set.begin(),
+ table->foreign_set.end(),
+ dict_foreign_with_foreign_index(index));
- is_referenced = TRUE;
- goto func_exit;
- }
+ is_referenced = (it != table->foreign_set.end());
- }
-
-func_exit:
if (froze_data_dict) {
row_mysql_unfreeze_data_dictionary(trx);
}
@@ -361,13 +356,12 @@ wsrep_row_upd_check_foreign_constraints(
ibool opened = FALSE;
if (table->foreign_set.empty()) {
-
return(DB_SUCCESS);
}
trx = thr_get_trx(thr);
- /* TODO: make native slave thread bail out here */
+ /* TODO: make native slave thread bail out here */
rec = btr_pcur_get_rec(pcur);
ut_ad(rec_offs_validate(rec, index, offsets));
@@ -387,12 +381,11 @@ wsrep_row_upd_check_foreign_constraints(
row_mysql_freeze_data_dictionary(trx);
}
- for (dict_foreign_set::iterator it= table->foreign_set.begin();
+ for (dict_foreign_set::iterator it = table->foreign_set.begin();
it != table->foreign_set.end();
- ++ it)
- {
- foreign= *it;
+ ++it) {
+ foreign = *it;
/* Note that we may have an update which updates the index
record, but does NOT update the first fields which are
referenced in a foreign key constraint. Then the update does
@@ -412,11 +405,6 @@ wsrep_row_upd_check_foreign_constraints(
opened = TRUE;
}
- if (foreign->referenced_table) {
- os_atomic_increment_ulint(
- &foreign->referenced_table->n_foreign_key_checks_running,1);
- }
-
/* NOTE that if the thread ends up waiting for a lock
we will release dict_operation_lock temporarily!
But the counter on the table protects 'foreign' from
@@ -426,9 +414,6 @@ wsrep_row_upd_check_foreign_constraints(
TRUE, foreign, table, entry, thr);
if (foreign->referenced_table) {
- os_atomic_decrement_ulint(
- &foreign->referenced_table->n_foreign_key_checks_running, 1);
-
if (opened == TRUE) {
dict_table_close(foreign->referenced_table, TRUE, FALSE);
opened = FALSE;
@@ -436,11 +421,9 @@ wsrep_row_upd_check_foreign_constraints(
}
if (err != DB_SUCCESS) {
-
goto func_exit;
}
}
-
}
err = DB_SUCCESS;
@@ -451,8 +434,6 @@ func_exit:
mem_heap_free(heap);
- DEBUG_SYNC_C("foreign_constraint_check_for_update_done");
-
return(err);
}
#endif /* WITH_WSREP */
@@ -570,6 +551,13 @@ row_upd_changes_field_size_or_external(
for (i = 0; i < n_fields; i++) {
upd_field = upd_get_nth_field(update, i);
+ /* We should ignore virtual field if the index is not
+ a virtual index */
+ if (upd_fld_is_virtual_col(upd_field)
+ && dict_index_has_virtual(index) != DICT_VIRTUAL) {
+ continue;
+ }
+
new_val = &(upd_field->new_val);
new_len = dfield_get_len(new_val);
@@ -815,7 +803,13 @@ row_upd_index_write_log(
len = dfield_get_len(new_val);
- log_ptr += mach_write_compressed(log_ptr, upd_field->field_no);
+ /* If this is a virtual column, mark it using special
+ field_no */
+ ulint field_no = upd_fld_is_virtual_col(upd_field)
+ ? REC_MAX_N_FIELDS + upd_field->field_no
+ : upd_field->field_no;
+
+ log_ptr += mach_write_compressed(log_ptr, field_no);
log_ptr += mach_write_compressed(log_ptr, len);
if (len != UNIV_SQL_NULL) {
@@ -891,6 +885,13 @@ row_upd_index_parse(
return(NULL);
}
+ /* Check if this is a virtual column, mark the prtype
+ if that is the case */
+ if (field_no >= REC_MAX_N_FIELDS) {
+ new_val->type.prtype |= DATA_VIRTUAL;
+ field_no -= REC_MAX_N_FIELDS;
+ }
+
upd_field->field_no = field_no;
len = mach_parse_compressed(&ptr, end_ptr);
@@ -987,23 +988,32 @@ row_upd_build_sec_rec_difference_binary(
return(update);
}
-/***************************************************************//**
-Builds an update vector from those fields, excluding the roll ptr and
+/** Builds an update vector from those fields, excluding the roll ptr and
trx id fields, which in an index entry differ from a record that has
the equal ordering fields. NOTE: we compare the fields as binary strings!
+@param[in] index clustered index
+@param[in] entry clustered index entry to insert
+@param[in] rec clustered index record
+@param[in] offsets rec_get_offsets(rec,index), or NULL
+@param[in] no_sys skip the system columns
+ DB_TRX_ID and DB_ROLL_PTR
+@param[in] trx transaction (for diagnostics),
+ or NULL
+@param[in] heap memory heap from which allocated
+@param[in] mysql_table NULL, or mysql table object when
+ user thread invokes dml
@return own: update vector of differing fields, excluding roll ptr and
trx id */
upd_t*
row_upd_build_difference_binary(
-/*============================*/
- dict_index_t* index, /*!< in: clustered index */
- const dtuple_t* entry, /*!< in: entry to insert */
- const rec_t* rec, /*!< in: clustered index record */
- const ulint* offsets,/*!< in: rec_get_offsets(rec,index), or NULL */
- bool no_sys, /*!< in: skip the system columns
- DB_TRX_ID and DB_ROLL_PTR */
- trx_t* trx, /*!< in: transaction */
- mem_heap_t* heap) /*!< in: memory heap from which allocated */
+ dict_index_t* index,
+ const dtuple_t* entry,
+ const rec_t* rec,
+ const ulint* offsets,
+ bool no_sys,
+ trx_t* trx,
+ mem_heap_t* heap,
+ TABLE* mysql_table)
{
upd_field_t* upd_field;
dfield_t* dfield;
@@ -1072,11 +1082,21 @@ row_upd_build_difference_binary(
}
}
- /* Check the virtual columns updates, but there must be some non-virtual
- column (base columns) change */
- if (n_diff && n_v_fld) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
+ /* Check the virtual columns updates. Even if there is no non-virtual
+ column (base columns) change, we will still need to build the
+ indexed virtual column value so that undo log would log them (
+ for purge/mvcc purpose) */
+ if (n_v_fld > 0) {
row_ext_t* ext;
mem_heap_t* v_heap = NULL;
+ THD* thd;
+
+ if (trx == NULL) {
+ thd = current_thd;
+ } else {
+ thd = trx->mysql_thd;
+ }
ut_ad(!update->old_vrow);
@@ -1097,8 +1117,9 @@ row_upd_build_difference_binary(
dfield = dtuple_get_nth_v_field(entry, i);
dfield_t* vfield = innobase_get_computed_value(
- update->old_vrow, col, index, NULL,
- &v_heap, heap, NULL, false);
+ update->old_vrow, col, index,
+ &v_heap, heap, NULL, thd, mysql_table,
+ NULL, NULL, NULL);
if (!dfield_data_is_binary_equal(
dfield, vfield->len,
@@ -1126,6 +1147,7 @@ row_upd_build_difference_binary(
mem_heap_free(v_heap);
}
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
update->n_fields = n_diff;
ut_ad(update->validate());
@@ -1431,7 +1453,16 @@ row_upd_replace_vcol(
/* If there is no index on the column, do not bother for
value update */
if (!col->m_col.ord_part) {
- continue;
+ dict_index_t* clust_index
+ = dict_table_get_first_index(table);
+
+ /* Skip the column if there is no online alter
+ table in progress or it is not being indexed
+ in new table */
+ if (!dict_index_is_online_ddl(clust_index)
+ || !row_log_col_is_indexed(clust_index, col_no)) {
+ continue;
+ }
}
dfield = dtuple_get_nth_v_field(row, col_no);
@@ -1461,6 +1492,7 @@ row_upd_replace_vcol(
}
bool first_v_col = true;
+ bool is_undo_log = true;
/* We will read those unchanged (but indexed) virtual columns in */
if (ptr != NULL) {
@@ -1482,7 +1514,8 @@ row_upd_replace_vcol(
if (is_v) {
ptr = trx_undo_read_v_idx(
- table, ptr, first_v_col, &field_no);
+ table, ptr, first_v_col, &is_undo_log,
+ &field_no);
first_v_col = false;
}
@@ -2034,14 +2067,18 @@ row_upd_eval_new_vals(
}
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
/** Stores to the heap the virtual columns that need for any indexes
-@param[in,out] node row update node
-@param[in] update an update vector if it is update */
-static
+@param[in,out] node row update node
+@param[in] update an update vector if it is update
+@param[in] thd mysql thread handle
+@param[in,out] mysql_table mysql table object */
void
row_upd_store_v_row(
upd_node_t* node,
- const upd_t* update)
+ const upd_t* update,
+ THD* thd,
+ TABLE* mysql_table)
{
mem_heap_t* heap = NULL;
dict_index_t* index = dict_table_get_first_index(node->table);
@@ -2078,19 +2115,28 @@ row_upd_store_v_row(
/* If this is an update, then the value
should be in update->old_vrow */
if (update) {
- ut_ad(update->old_vrow);
- dfield_t* vfield
- = dtuple_get_nth_v_field(
- update->old_vrow,
- col_no);
- dfield_copy_data(dfield, vfield);
+ if (update->old_vrow == NULL) {
+ /* This only happens in
+ cascade update. And virtual
+ column can't be affected,
+ so it is Ok to set it to NULL */
+ ut_ad(!node->cascade_top);
+ dfield_set_null(dfield);
+ } else {
+ dfield_t* vfield
+ = dtuple_get_nth_v_field(
+ update->old_vrow,
+ col_no);
+ dfield_copy_data(dfield, vfield);
+ }
} else {
/* Need to compute, this happens when
deleting row */
innobase_get_computed_value(
- node->row, col, index, NULL,
+ node->row, col, index,
&heap, node->heap, NULL,
- false);
+ thd, mysql_table, NULL,
+ NULL, NULL);
}
}
}
@@ -2100,13 +2146,18 @@ row_upd_store_v_row(
mem_heap_free(heap);
}
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
-/***********************************************************//**
-Stores to the heap the row on which the node->pcur is positioned. */
+/** Stores to the heap the row on which the node->pcur is positioned.
+@param[in] node row update node
+@param[in] thd mysql thread handle
+@param[in,out] mysql_table NULL, or mysql table object when
+ user thread invokes dml */
void
row_upd_store_row(
-/*==============*/
- upd_node_t* node) /*!< in: row update node */
+ upd_node_t* node,
+ THD* thd,
+ TABLE* mysql_table)
{
dict_index_t* clust_index;
rec_t* rec;
@@ -2145,10 +2196,12 @@ row_upd_store_row(
node->row = row_build(ROW_COPY_DATA, clust_index, rec, offsets,
NULL, NULL, NULL, ext, node->heap);
+#ifdef MYSQL_VIRTUAL_COLUMNS
if (node->table->n_v_cols) {
- row_upd_store_v_row(node, node->is_delete
- ? NULL : node->update);
+ row_upd_store_v_row(node, node->is_delete ? NULL : node->update,
+ thd, mysql_table);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
if (node->is_delete) {
node->upd_row = NULL;
@@ -2215,7 +2268,7 @@ row_upd_sec_index_entry(
referenced = row_upd_index_is_referenced(index, trx);
#ifdef WITH_WSREP
- ibool foreign = wsrep_row_upd_index_is_foreign(index, trx);
+ bool foreign = wsrep_row_upd_index_is_foreign(index, trx);
#endif /* WITH_WSREP */
heap = mem_heap_create(1024);
@@ -2362,50 +2415,39 @@ row_upd_sec_index_entry(
case ROW_FOUND:
ut_ad(err == DB_SUCCESS);
- que_node_t *parent = que_node_get_parent(node);
/* Delete mark the old index record; it can already be
delete marked if we return after a lock wait in
row_ins_sec_index_entry() below */
if (!rec_get_deleted_flag(
rec, dict_table_is_comp(index->table))) {
+
+ que_node_t *parent = que_node_get_parent(node);
+
err = btr_cur_del_mark_set_sec_rec(
flags, btr_cur, TRUE, thr, &mtr);
if (err != DB_SUCCESS) {
break;
}
- }
-
- ut_ad(err == DB_SUCCESS);
-
- if (referenced) {
-
- ulint* offsets;
-
- offsets = rec_get_offsets(
- rec, index, NULL, ULINT_UNDEFINED,
- &heap);
-
- /* NOTE that the following call loses
- the position of pcur ! */
- err = row_upd_check_references_constraints(
- node, &pcur, index->table,
- index, offsets, thr, &mtr);
- }
#ifdef WITH_WSREP
if (err == DB_SUCCESS && !referenced &&
!(parent && que_node_get_type(parent) ==
QUE_NODE_UPDATE &&
- ((upd_node_t*)parent)->cascade_node == node) &&
- foreign
- ) {
+ (std::find(((upd_node_t*)parent)->cascade_upd_nodes->begin(),
+ ((upd_node_t*)parent)->cascade_upd_nodes->end(),
+ node) ==
+ ((upd_node_t*)parent)->cascade_upd_nodes->end())) &&
+ foreign
+ ) {
ulint* offsets =
rec_get_offsets(
rec, index, NULL, ULINT_UNDEFINED,
&heap);
+
err = wsrep_row_upd_check_foreign_constraints(
node, &pcur, index->table,
index, offsets, thr, &mtr);
+
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
@@ -2413,18 +2455,38 @@ row_upd_sec_index_entry(
break;
case DB_DEADLOCK:
if (wsrep_debug) {
- ib::info() <<
- "WSREP: sec index FK check fail for deadlock";
+ ib::warn() << "WSREP: sec index FK check fail for deadlock"
+ << " index " << index->name()
+ << " table " << index->table->name.m_name;
}
break;
default:
- ib::info() <<
- "WSREP: referenced FK check fail: " << err;
+ ib::error() << "WSREP: referenced FK check fail: " << err
+ << " index " << index->name()
+ << " table " << index->table->name.m_name;
+
break;
}
}
#endif /* WITH_WSREP */
- break;
+ }
+
+ ut_ad(err == DB_SUCCESS);
+
+ if (referenced) {
+
+ ulint* offsets;
+
+ offsets = rec_get_offsets(
+ rec, index, NULL, ULINT_UNDEFINED,
+ &heap);
+
+ /* NOTE that the following call loses
+ the position of pcur ! */
+ err = row_upd_check_references_constraints(
+ node, &pcur, index->table,
+ index, offsets, thr, &mtr);
+ }
}
btr_pcur_close(&pcur);
@@ -2596,7 +2658,9 @@ row_upd_clust_rec_by_insert(
dberr_t err;
rec_t* rec;
ulint* offsets = NULL;
+#ifdef WITH_WSREP
que_node_t *parent = que_node_get_parent(node);
+#endif
ut_ad(node);
ut_ad(dict_index_is_clust(index));
@@ -2687,12 +2751,14 @@ check_fk:
#ifdef WITH_WSREP
if (!referenced &&
!(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
- ((upd_node_t*)parent)->cascade_node == node) &&
+ (std::find(((upd_node_t*)parent)->cascade_upd_nodes->begin(),
+ ((upd_node_t*)parent)->cascade_upd_nodes->end(),
+ node) ==
+ ((upd_node_t*)parent)->cascade_upd_nodes->end())) &&
foreign
) {
err = wsrep_row_upd_check_foreign_constraints(
node, pcur, table, index, offsets, thr, mtr);
-
switch (err) {
case DB_SUCCESS:
case DB_NO_REFERENCED_ROW:
@@ -2700,15 +2766,19 @@ check_fk:
break;
case DB_DEADLOCK:
if (wsrep_debug) {
- ib::info() <<
- "WSREP: insert FK check fail for deadlock";
+ ib::warn() << "WSREP: sec index FK check fail for deadlock"
+ << " index " << index->name()
+ << " table " << index->table->name.m_name;
}
break;
default:
- ib::info() <<
- "WSREP: referenced FK check fail: " << err;
+ ib::error() << "WSREP: referenced FK check fail: " << err
+ << " index " << index->name()
+ << " table " << index->table->name.m_name;
+
break;
}
+
if (err != DB_SUCCESS) {
goto err_exit;
}
@@ -2900,8 +2970,9 @@ row_upd_del_mark_clust_rec(
btr_cur_t* btr_cur;
dberr_t err;
rec_t* rec;
+#ifdef WITH_WSREP
que_node_t *parent = que_node_get_parent(node);
-
+#endif
ut_ad(node);
ut_ad(dict_index_is_clust(index));
ut_ad(node->is_delete);
@@ -2912,7 +2983,8 @@ row_upd_del_mark_clust_rec(
/* Store row because we have to build also the secondary index
entries */
- row_upd_store_row(node);
+ row_upd_store_row(node, thr_get_trx(thr)->mysql_thd,
+ thr->prebuilt ? thr->prebuilt->m_mysql_table : NULL);
/* Mark the clustered index record deleted; we do not have to check
locks, because we assume that we have an x-lock on the record */
@@ -2932,7 +3004,10 @@ row_upd_del_mark_clust_rec(
#ifdef WITH_WSREP
if (err == DB_SUCCESS && !referenced &&
!(parent && que_node_get_type(parent) == QUE_NODE_UPDATE &&
- ((upd_node_t*)parent)->cascade_node == node) &&
+ (std::find(((upd_node_t*)parent)->cascade_upd_nodes->begin(),
+ ((upd_node_t*)parent)->cascade_upd_nodes->end(),
+ node) ==
+ ((upd_node_t*)parent)->cascade_upd_nodes->end())) &&
thr_get_trx(thr) &&
foreign
) {
@@ -2945,13 +3020,16 @@ row_upd_del_mark_clust_rec(
break;
case DB_DEADLOCK:
if (wsrep_debug) {
- ib::info() <<
- "WSREP: clust rec FK check fail for deadlock";
+ ib::warn() << "WSREP: sec index FK check fail for deadlock"
+ << " index " << index->name()
+ << " table " << index->table->name.m_name;
}
break;
default:
- ib::info() <<
- "WSREP: clust rec referenced FK check fail: " << err;
+ ib::error() << "WSREP: referenced FK check fail: " << err
+ << " index " << index->name()
+ << " table " << index->table->name.m_name;
+
break;
}
}
@@ -2985,12 +3063,13 @@ row_upd_clust_step(
ibool referenced;
ulint flags = 0;
ibool foreign = FALSE;
+ trx_t* trx = thr_get_trx(thr);
rec_offs_init(offsets_);
index = dict_table_get_first_index(node->table);
- referenced = row_upd_index_is_referenced(index, thr_get_trx(thr));
+ referenced = row_upd_index_is_referenced(index, trx);
#ifdef WITH_WSREP
foreign = wsrep_row_upd_index_is_foreign(
@@ -3128,7 +3207,8 @@ row_upd_clust_step(
goto exit_func;
}
- row_upd_store_row(node);
+ row_upd_store_row(node, trx->mysql_thd,
+ thr->prebuilt ? thr->prebuilt->m_mysql_table : NULL);
if (row_upd_changes_ord_field_binary(index, node->update, thr,
node->row, node->ext)) {
@@ -3179,7 +3259,6 @@ to this node, we assume that we have a persistent cursor which was on a
record, and the position of the cursor is stored in the cursor.
@return DB_SUCCESS if operation successfully completed, else error
code or DB_LOCK_WAIT */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_upd(
/*====*/
@@ -3227,6 +3306,9 @@ row_upd(
}
}
+ DEBUG_SYNC_C_IF_THD(thr_get_trx(thr)->mysql_thd,
+ "after_row_upd_clust");
+
if (node->index == NULL
|| (!node->is_delete
&& (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE))) {
@@ -3234,9 +3316,6 @@ row_upd(
DBUG_RETURN(DB_SUCCESS);
}
- DEBUG_SYNC_C_IF_THD(thr_get_trx(thr)->mysql_thd,
- "after_row_upd_clust");
-
DBUG_EXECUTE_IF("row_upd_skip_sec", node->index = NULL;);
do {
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index da342701d4b..fd17683fb48 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1997, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1997, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -53,16 +53,20 @@ Created 2/6/1997 Heikki Tuuri
the cluster index
@param[in] index the secondary index
@param[in] row the cluster index row in dtuple form
+@param[in] ext externally stored column prefix or NULL
@param[in] ientry the secondary index entry
+@param[in,out] heap heap used to build virtual dtuple
@param[in,out] n_non_v_col number of non-virtual columns in the index
@return true if all matches, false otherwise */
static
bool
row_vers_non_vc_match(
- dict_index_t* index,
- const dtuple_t* row,
- const dtuple_t* ientry,
- ulint* n_non_v_col);
+ dict_index_t* index,
+ const dtuple_t* row,
+ const row_ext_t* ext,
+ const dtuple_t* ientry,
+ mem_heap_t* heap,
+ ulint* n_non_v_col);
/*****************************************************************//**
Finds out if an active transaction has inserted or modified a secondary
index record.
@@ -90,6 +94,8 @@ row_vers_impl_x_locked_low(
ulint* clust_offsets;
mem_heap_t* heap;
dtuple_t* ientry = NULL;
+ mem_heap_t* v_heap = NULL;
+ const dtuple_t* cur_vrow = NULL;
DBUG_ENTER("row_vers_impl_x_locked_low");
@@ -126,7 +132,14 @@ row_vers_impl_x_locked_low(
if (dict_index_has_virtual(index)) {
ulint n_ext;
- ientry = row_rec_to_index_entry(rec, index, offsets, &n_ext, heap);
+ ulint est_size = DTUPLE_EST_ALLOC(index->n_fields);
+
+ /* Allocate the dtuple for virtual columns extracted from undo
+ log with its own heap, so to avoid it being freed as we
+ iterating in the version loop below. */
+ v_heap = mem_heap_create(est_size);
+ ientry = row_rec_to_index_entry(
+ rec, index, offsets, &n_ext, v_heap);
}
/* We look up if some earlier version, which was modified by
@@ -148,7 +161,6 @@ row_vers_impl_x_locked_low(
trx_id_t prev_trx_id;
mem_heap_t* old_heap = heap;
const dtuple_t* vrow = NULL;
- bool skip_cmp = false;
/* We keep the semaphore in mtr on the clust_rec page, so
that no other transaction can update it and get an
@@ -215,28 +227,34 @@ row_vers_impl_x_locked_low(
NULL, NULL, NULL, &ext, heap);
if (dict_index_has_virtual(index)) {
- if (!vrow) {
- ulint n_non_v_col = 0;
+ if (vrow) {
+ /* Keep the virtual row info for the next
+ version */
+ cur_vrow = dtuple_copy(vrow, v_heap);
+ dtuple_dup_v_fld(cur_vrow, v_heap);
+ }
- if (!row_vers_non_vc_match(
- index, row, ientry, &n_non_v_col)) {
- if (!rec_del) {
- break;
- }
- }
+ if (!cur_vrow) {
+ ulint n_non_v_col = 0;
/* If the indexed virtual columns has changed,
there must be log record to generate vrow.
Otherwise, it is not changed, so no need
to compare */
- skip_cmp = true;
- if (rec_del != vers_del) {
+ if (row_vers_non_vc_match(
+ index, row, ext, ientry, heap,
+ &n_non_v_col) == 0) {
+ if (rec_del != vers_del) {
+ break;
+ }
+ } else if (!rec_del) {
break;
}
+
goto result_check;
} else {
- ut_ad(row->n_v_fields == vrow->n_v_fields);
- dtuple_copy_v_fields(row, vrow);
+ ut_ad(row->n_v_fields == cur_vrow->n_v_fields);
+ dtuple_copy_v_fields(row, cur_vrow);
}
}
@@ -260,7 +278,7 @@ row_vers_impl_x_locked_low(
/* We check if entry and rec are identified in the alphabetical
ordering */
- if (!skip_cmp && 0 == cmp_dtuple_rec(entry, rec, offsets)) {
+ if (0 == cmp_dtuple_rec(entry, rec, offsets)) {
/* The delete marks of rec and prev_version should be
equal for rec to be in the state required by
prev_version */
@@ -303,6 +321,10 @@ result_check:
DBUG_PRINT("info", ("Implicit lock is held by trx:" TRX_ID_FMT, trx_id));
+ if (v_heap != NULL) {
+ mem_heap_free(v_heap);
+ }
+
mem_heap_free(heap);
DBUG_RETURN(trx);
}
@@ -394,16 +416,20 @@ row_vers_must_preserve_del_marked(
the cluster index
@param[in] index the secondary index
@param[in] row the cluster index row in dtuple form
+@param[in] ext externally stored column prefix or NULL
@param[in] ientry the secondary index entry
+@param[in,out] heap heap used to build virtual dtuple
@param[in,out] n_non_v_col number of non-virtual columns in the index
@return true if all matches, false otherwise */
static
bool
row_vers_non_vc_match(
- dict_index_t* index,
- const dtuple_t* row,
- const dtuple_t* ientry,
- ulint* n_non_v_col)
+ dict_index_t* index,
+ const dtuple_t* row,
+ const row_ext_t* ext,
+ const dtuple_t* ientry,
+ mem_heap_t* heap,
+ ulint* n_non_v_col)
{
const dfield_t* field1;
dfield_t* field2;
@@ -412,20 +438,23 @@ row_vers_non_vc_match(
*n_non_v_col = 0;
+ /* Build index entry out of row */
+ dtuple_t* nentry = row_build_index_entry(row, ext, index, heap);
+
for (ulint i = 0; i < n_fields; i++) {
const dict_field_t* ind_field = dict_index_get_nth_field(
index, i);
const dict_col_t* col = ind_field->col;
+ /* Only check non-virtual columns */
if (dict_col_is_virtual(col)) {
continue;
}
if (ret) {
field1 = dtuple_get_nth_field(ientry, i);
- field2 = dtuple_get_nth_field(
- row, dict_col_get_no(col));
+ field2 = dtuple_get_nth_field(nentry, i);
if (cmp_dfield_dfield(field1, field2) != 0) {
ret = false;
@@ -438,9 +467,10 @@ row_vers_non_vc_match(
return(ret);
}
+#ifdef MYSQL_VIRTUAL_COLUMNS
/** build virtual column value from current cluster index record data
@param[in,out] row the cluster index row in dtuple form
-@param[in] clust_index cluster index
+@param[in] clust_index clustered index
@param[in] index the secondary index
@param[in] heap heap used to build virtual dtuple */
static
@@ -463,8 +493,9 @@ row_vers_build_clust_v_col(
ind_field->col);
innobase_get_computed_value(
- row, col, clust_index, NULL, &local_heap,
- heap, NULL, true);
+ row, col, clust_index, &local_heap,
+ heap, NULL, current_thd, NULL, NULL,
+ NULL, NULL);
}
}
@@ -472,6 +503,114 @@ row_vers_build_clust_v_col(
mem_heap_free(local_heap);
}
}
+/** Build latest virtual column data from undo log
+@param[in] in_purge whether this is the purge thread
+@param[in] rec clustered index record
+@param[in] clust_index clustered index
+@param[in,out] clust_offsets offsets on the clustered index record
+@param[in] index the secondary index
+@param[in] roll_ptr the rollback pointer for the purging record
+@param[in] trx_id trx id for the purging record
+@param[in,out] v_heap heap used to build vrow
+@param[out] v_row dtuple holding the virtual rows
+@param[in,out] mtr mtr holding the latch on rec */
+static
+void
+row_vers_build_cur_vrow_low(
+ bool in_purge,
+ const rec_t* rec,
+ dict_index_t* clust_index,
+ ulint* clust_offsets,
+ dict_index_t* index,
+ roll_ptr_t roll_ptr,
+ trx_id_t trx_id,
+ mem_heap_t* v_heap,
+ const dtuple_t**vrow,
+ mtr_t* mtr)
+{
+ const rec_t* version;
+ rec_t* prev_version;
+ mem_heap_t* heap = NULL;
+ ulint num_v = dict_table_get_n_v_cols(index->table);
+ const dfield_t* field;
+ ulint i;
+ bool all_filled = false;
+
+ *vrow = dtuple_create_with_vcol(v_heap, 0, num_v);
+ dtuple_init_v_fld(*vrow);
+
+ for (i = 0; i < num_v; i++) {
+ dfield_get_type(dtuple_get_nth_v_field(*vrow, i))->mtype
+ = DATA_MISSING;
+ }
+
+ version = rec;
+
+ /* If this is called by purge thread, set TRX_UNDO_PREV_IN_PURGE
+ bit to search the undo log until we hit the current undo log with
+ roll_ptr */
+ const ulint status = in_purge
+ ? TRX_UNDO_PREV_IN_PURGE | TRX_UNDO_GET_OLD_V_VALUE
+ : TRX_UNDO_GET_OLD_V_VALUE;
+
+ while (!all_filled) {
+ mem_heap_t* heap2 = heap;
+ heap = mem_heap_create(1024);
+ roll_ptr_t cur_roll_ptr = row_get_rec_roll_ptr(
+ version, clust_index, clust_offsets);
+
+ trx_undo_prev_version_build(
+ rec, mtr, version, clust_index, clust_offsets,
+ heap, &prev_version, NULL, vrow, status);
+
+ if (heap2) {
+ mem_heap_free(heap2);
+ }
+
+ if (!prev_version) {
+ /* Versions end here */
+ break;
+ }
+
+ clust_offsets = rec_get_offsets(prev_version, clust_index,
+ NULL, ULINT_UNDEFINED, &heap);
+
+ ulint entry_len = dict_index_get_n_fields(index);
+
+ all_filled = true;
+
+ for (i = 0; i < entry_len; i++) {
+ const dict_field_t* ind_field
+ = dict_index_get_nth_field(index, i);
+ const dict_col_t* col = ind_field->col;
+
+ if (!dict_col_is_virtual(col)) {
+ continue;
+ }
+
+ const dict_v_col_t* v_col
+ = reinterpret_cast<const dict_v_col_t*>(col);
+ field = dtuple_get_nth_v_field(*vrow, v_col->v_pos);
+
+ if (dfield_get_type(field)->mtype == DATA_MISSING) {
+ all_filled = false;
+ break;
+ }
+
+ }
+
+ trx_id_t rec_trx_id = row_get_rec_trx_id(
+ prev_version, clust_index, clust_offsets);
+
+ if (rec_trx_id < trx_id || roll_ptr == cur_roll_ptr) {
+ break;
+ }
+
+ version = prev_version;
+ }
+
+ mem_heap_free(heap);
+}
/** Check a virtual column value index secondary virtual index matches
that of current cluster index record, which is recreated from information
@@ -479,6 +618,7 @@ stored in undo log
@param[in] in_purge called by purge thread
@param[in] rec record in the clustered index
@param[in] row the cluster index row in dtuple form
+@param[in] ext externally stored column prefix or NULL
@param[in] clust_index cluster index
@param[in] clust_offsets offsets on the cluster record
@param[in] index the secondary index
@@ -495,6 +635,7 @@ row_vers_vc_matches_cluster(
bool in_purge,
const rec_t* rec,
const dtuple_t* row,
+ row_ext_t* ext,
dict_index_t* clust_index,
ulint* clust_offsets,
dict_index_t* index,
@@ -519,15 +660,17 @@ row_vers_vc_matches_cluster(
dfield_t* field2;
ulint i;
+ tuple_heap = mem_heap_create(1024);
+
/* First compare non-virtual columns (primary keys) */
- if (!row_vers_non_vc_match(index, row, ientry, &n_non_v_col)) {
+ if (!row_vers_non_vc_match(index, row, ext, ientry, tuple_heap,
+ &n_non_v_col)) {
+ mem_heap_free(tuple_heap);
return(false);
}
ut_ad(n_fields > n_non_v_col);
- tuple_heap = mem_heap_create(1024);
-
*vrow = dtuple_create_with_vcol(v_heap ? v_heap : tuple_heap, 0, num_v);
dtuple_init_v_fld(*vrow);
@@ -551,6 +694,9 @@ row_vers_vc_matches_cluster(
roll_ptr_t cur_roll_ptr = row_get_rec_roll_ptr(
version, clust_index, clust_offsets);
+ ut_ad(cur_roll_ptr != 0);
+ ut_ad(in_purge == (roll_ptr != 0));
+
trx_undo_prev_version_build(
rec, mtr, version, clust_index, clust_offsets,
heap, &prev_version, NULL, vrow, status);
@@ -663,11 +809,6 @@ row_vers_build_cur_vrow(
mtr_t* mtr)
{
const dtuple_t* cur_vrow = NULL;
- row_ext_t* ext;
-
- dtuple_t* row = row_build(ROW_COPY_POINTERS, clust_index,
- rec, *clust_offsets,
- NULL, NULL, NULL, &ext, heap);
roll_ptr_t t_roll_ptr = row_get_rec_roll_ptr(
rec, clust_index, *clust_offsets);
@@ -675,21 +816,32 @@ row_vers_build_cur_vrow(
/* if the row is newly inserted, then the virtual
columns need to be computed */
if (trx_undo_roll_ptr_is_insert(t_roll_ptr)) {
+
+ ut_ad(!rec_get_deleted_flag(rec, page_rec_is_comp(rec)));
+
+ /* This is a newly inserted record and cannot
+ be deleted, So the externally stored field
+ cannot be freed yet. */
+ dtuple_t* row = row_build(ROW_COPY_POINTERS, clust_index,
+ rec, *clust_offsets,
+ NULL, NULL, NULL, NULL, heap);
+
row_vers_build_clust_v_col(
row, clust_index, index, heap);
cur_vrow = dtuple_copy(row, v_heap);
dtuple_dup_v_fld(cur_vrow, v_heap);
} else {
- row_vers_vc_matches_cluster(
- in_purge, rec, row, clust_index, *clust_offsets,
- index, ientry, roll_ptr,
- trx_id, v_heap, &cur_vrow, mtr);
+ /* Try to fetch virtual column data from undo log */
+ row_vers_build_cur_vrow_low(
+ in_purge, rec, clust_index, *clust_offsets,
+ index, roll_ptr, trx_id, v_heap, &cur_vrow, mtr);
}
*clust_offsets = rec_get_offsets(rec, clust_index, NULL,
ULINT_UNDEFINED, &heap);
return(cur_vrow);
}
+#endif /* MYSQL_VIRTUAL_COLUMNS */
/*****************************************************************//**
Finds out if a version of the record, where the version >= the current
@@ -760,6 +912,9 @@ row_vers_old_has_index_entry(
NULL, NULL, NULL, &ext, heap);
if (dict_index_has_virtual(index)) {
+
+#ifdef MYSQL_VIRTUAL_COLUMNS
+
#ifdef DBUG_OFF
# define dbug_v_purge false
#else /* DBUG_OFF */
@@ -794,7 +949,7 @@ row_vers_old_has_index_entry(
}
} else {
if (row_vers_vc_matches_cluster(
- also_curr, rec, row, clust_index,
+ also_curr, rec, row, ext, clust_index,
clust_offsets, index, ientry, roll_ptr,
trx_id, NULL, &vrow, mtr)) {
mem_heap_free(heap);
@@ -808,6 +963,7 @@ row_vers_old_has_index_entry(
}
clust_offsets = rec_get_offsets(rec, clust_index, NULL,
ULINT_UNDEFINED, &heap);
+#endif /* MYSQL_VIRTUAL_COLUMNS */
} else {
entry = row_build_index_entry(
@@ -845,6 +1001,7 @@ row_vers_old_has_index_entry(
}
}
} else if (dict_index_has_virtual(index)) {
+#ifdef MYSQL_VIRTUAL_COLUMNS
/* The current cluster index record could be
deleted, but the previous version of it might not. We will
need to get the virtual column data from undo record
@@ -852,6 +1009,7 @@ row_vers_old_has_index_entry(
cur_vrow = row_vers_build_cur_vrow(
also_curr, rec, clust_index, &clust_offsets,
index, ientry, roll_ptr, trx_id, heap, v_heap, mtr);
+#endif /* MYSQL_VIRTUAL_COLUMNS */
}
version = rec;
diff --git a/storage/innobase/srv/srv0conc.cc b/storage/innobase/srv/srv0conc.cc
index 96f17ea3359..a362873fee3 100644
--- a/storage/innobase/srv/srv0conc.cc
+++ b/storage/innobase/srv/srv0conc.cc
@@ -152,6 +152,19 @@ srv_conc_enter_innodb_with_atomics(
return;
}
+ if (srv_thread_concurrency == 0) {
+
+ if (notified_mysql) {
+
+ (void) os_atomic_decrement_lint(
+ &srv_conc.n_waiting, 1);
+
+ thd_wait_end(trx->mysql_thd);
+ }
+
+ return;
+ }
+
if (srv_conc.n_active < (lint) srv_thread_concurrency) {
ulint n_active;
diff --git a/storage/innobase/srv/srv0mon.cc b/storage/innobase/srv/srv0mon.cc
index c03ce6dcb35..6d213a2c761 100644
--- a/storage/innobase/srv/srv0mon.cc
+++ b/storage/innobase/srv/srv0mon.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2010, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2010, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2012, Facebook Inc.
Copyright (c) 2013, 2016, MariaDB Corporation
@@ -1559,7 +1559,10 @@ srv_mon_set_module_control(
module */
set_current_module = FALSE;
} else if (module_id == MONITOR_ALL_COUNTER) {
- continue;
+ if (!(innodb_counter_info[ix].monitor_type
+ & MONITOR_GROUP_MODULE)) {
+ continue;
+ }
} else {
/* Hitting the next module, stop */
break;
diff --git a/storage/innobase/srv/srv0srv.cc b/storage/innobase/srv/srv0srv.cc
index a20c3e6febd..f738bcaa22f 100644
--- a/storage/innobase/srv/srv0srv.cc
+++ b/storage/innobase/srv/srv0srv.cc
@@ -77,7 +77,6 @@ Created 10/8/1995 Heikki Tuuri
#include "ut0crc32.h"
#include "btr0defragment.h"
#include "ut0mem.h"
-
#include "fil0fil.h"
#include "fil0crypt.h"
#include "fil0pagecompress.h"
@@ -190,11 +189,6 @@ use simulated aio we build below with threads.
Currently we support native aio on windows and linux */
my_bool srv_use_native_aio = TRUE;
my_bool srv_numa_interleave = FALSE;
-
-#ifdef UNIV_DEBUG
-/** Force all user tables to use page compression. */
-ulong srv_debug_compress;
-#endif /* UNIV_DEBUG */
/* If this flag is TRUE, then we will use fallocate(PUCH_HOLE)
to the pages */
UNIV_INTERN my_bool srv_use_trim = FALSE;
@@ -209,6 +203,17 @@ UNIV_INTERN long srv_mtflush_threads = MTFLUSH_DEFAULT_WORKER;
/* If this flag is TRUE, then we will use multi threaded flush. */
UNIV_INTERN my_bool srv_use_mtflush = FALSE;
+#ifdef UNIV_DEBUG
+/** Force all user tables to use page compression. */
+ulong srv_debug_compress;
+/** Used by SET GLOBAL innodb_master_thread_disabled_debug = X. */
+my_bool srv_master_thread_disabled_debug;
+/** Event used to inform that master thread is disabled. */
+static os_event_t srv_master_thread_disabled_event;
+/** Debug variable to find if any background threads are adding
+to purge during slow shutdown. */
+extern bool trx_commit_disallowed;
+#endif /* UNIV_DEBUG */
/*------------------------- LOG FILES ------------------------ */
char* srv_log_group_home_dir = NULL;
@@ -258,7 +263,6 @@ UNIV_INTERN os_event_t srv_allow_writes_event;
/** Requested size in bytes */
ulint srv_buf_pool_size = ULINT_MAX;
-/** Minimum pool size in bytes */
const ulint srv_buf_pool_min_size = 5 * 1024 * 1024;
/** Default pool size in bytes */
const ulint srv_buf_pool_def_size = 128 * 1024 * 1024;
@@ -335,8 +339,8 @@ in the buffer pool to all database pages in the buffer pool smaller than
the following number. But it is not guaranteed that the value stays below
that during a time of heavy update/insert activity. */
-UNIV_INTERN double srv_max_buf_pool_modified_pct = 75.0;
-UNIV_INTERN double srv_max_dirty_pages_pct_lwm = 50.0;
+double srv_max_buf_pool_modified_pct = 75.0;
+double srv_max_dirty_pages_pct_lwm = 0.0;
/* This is the percentage of log capacity at which adaptive flushing,
if enabled, will kick in. */
@@ -411,7 +415,7 @@ UNIV_INTERN unsigned long long srv_stats_modified_counter = 0;
pages default true. */
UNIV_INTERN my_bool srv_stats_sample_traditional = TRUE;
-UNIV_INTERN ibool srv_use_doublewrite_buf = TRUE;
+ibool srv_use_doublewrite_buf = TRUE;
/** doublewrite buffer is 1MB is size i.e.: it can hold 128 16K pages.
The following parameter is the size of the buffer that is used for
@@ -428,7 +432,6 @@ UNIV_INTERN ulong srv_n_spin_wait_rounds = 15;
#else
UNIV_INTERN ulong srv_n_spin_wait_rounds = 30;
#endif
-
ulong srv_spin_wait_delay = 6;
ibool srv_priority_boost = TRUE;
@@ -466,13 +469,13 @@ UNIV_INTERN ulonglong srv_defragment_interval = 0;
/* Set the following to 0 if you want InnoDB to write messages on
stderr on startup/shutdown. */
-ibool srv_print_verbose_log = TRUE;
-my_bool srv_print_innodb_monitor = FALSE;
-my_bool srv_print_innodb_lock_monitor = FALSE;
-UNIV_INTERN my_bool srv_print_innodb_tablespace_monitor = FALSE;
-UNIV_INTERN my_bool srv_print_innodb_table_monitor = FALSE;
+ibool srv_print_verbose_log = TRUE;
+my_bool srv_print_innodb_monitor = FALSE;
+my_bool srv_print_innodb_lock_monitor = FALSE;
+my_bool srv_print_innodb_tablespace_monitor = FALSE;
+my_bool srv_print_innodb_table_monitor = FALSE;
/** If this flag is set tables without primary key are not allowed */
-UNIV_INTERN my_bool srv_force_primary_key = FALSE;
+my_bool srv_force_primary_key = FALSE;
/* Array of English strings describing the current state of an
i/o handler thread */
@@ -742,7 +745,8 @@ srv_print_master_thread_info(
srv_main_active_loops,
srv_main_shutdown_loops,
srv_main_idle_loops);
- fprintf(file, "srv_master_thread log flush and writes: %lu\n",
+ fprintf(file,
+ "srv_master_thread log flush and writes: " ULINTPF "\n",
srv_log_writes_and_flush);
}
@@ -1078,6 +1082,8 @@ srv_init(void)
srv_buf_resize_event = os_event_create(0);
+ ut_d(srv_master_thread_disabled_event = os_event_create(0));
+
/* page_zip_stat_per_index_mutex is acquired from:
1. page_zip_compress() (after SYNC_FSP)
2. page_zip_decompress()
@@ -1100,6 +1106,7 @@ srv_init(void)
srv_allow_writes_event = os_event_create(0);
os_event_set(srv_allow_writes_event);
#endif /* WITH_INNODB_DISALLOW_WRITES */
+
/* Initialize some INFORMATION SCHEMA internal structures */
trx_i_s_cache_init(trx_i_s_cache);
@@ -1135,6 +1142,11 @@ srv_free(void)
os_event_destroy(srv_buf_resize_event);
+#ifdef UNIV_DEBUG
+ os_event_destroy(srv_master_thread_disabled_event);
+ srv_master_thread_disabled_event = NULL;
+#endif /* UNIV_DEBUG */
+
trx_i_s_cache_free(trx_i_s_cache);
ut_free(srv_sys);
@@ -1375,8 +1387,10 @@ srv_printf_innodb_monitor(
fputs("--------------\n"
"ROW OPERATIONS\n"
"--------------\n", file);
- fprintf(file, "%ld queries inside InnoDB, %lu queries in queue\n",
- (long) srv_conc_get_active_threads(),
+ fprintf(file,
+ ULINTPF " queries inside InnoDB, "
+ ULINTPF " queries in queue\n",
+ srv_conc_get_active_threads(),
srv_conc_get_waiting_threads());
/* This is a dirty read, without holding trx_sys->mutex. */
@@ -1388,18 +1402,20 @@ srv_printf_innodb_monitor(
fprintf(file,
"%lu tablespace extents now reserved for"
" B-tree split operations\n",
- (ulong) n_reserved);
+ n_reserved);
}
fprintf(file,
"Process ID=" ULINTPF
- ", Main thread ID=" ULINTPF ", state: %s\n",
+ ", Main thread ID=" ULINTPF
+ ", state: %s\n",
srv_main_thread_process_no,
srv_main_thread_id,
srv_main_thread_op_info);
fprintf(file,
"Number of rows inserted " ULINTPF
- ", updated " ULINTPF ", deleted " ULINTPF
+ ", updated " ULINTPF
+ ", deleted " ULINTPF
", read " ULINTPF "\n",
(ulint) srv_stats.n_rows_inserted,
(ulint) srv_stats.n_rows_updated,
@@ -1539,13 +1555,12 @@ srv_export_innodb_status(void)
export_vars.innodb_buffer_pool_pages_misc =
buf_pool_get_n_pages() - LRU_len - free_len;
- /* JAN: TODO: MySQL 5.7
#ifdef HAVE_ATOMIC_BUILTINS
export_vars.innodb_have_atomic_builtins = 1;
#else
export_vars.innodb_have_atomic_builtins = 0;
#endif
- */
+
export_vars.innodb_page_size = UNIV_PAGE_SIZE;
export_vars.innodb_log_waits = srv_stats.log_waits;
@@ -1717,9 +1732,9 @@ DECLARE_THREAD(srv_monitor_thread)(
int64_t sig_count;
double time_elapsed;
time_t current_time;
+ time_t last_monitor_time;
time_t last_table_monitor_time;
time_t last_tablespace_monitor_time;
- time_t last_monitor_time;
ulint mutex_skipped;
ibool last_srv_print_monitor;
@@ -1874,7 +1889,7 @@ exit_func:
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -2002,7 +2017,7 @@ loop:
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -2092,8 +2107,10 @@ srv_any_background_threads_are_active(void)
os_event_set(lock_sys->timeout_event);
os_event_set(dict_stats_event);
os_event_set(srv_buf_resize_event);
- if (srv_scrub_log)
+
+ if (srv_scrub_log) {
os_event_set(log_scrub_event);
+ }
return(thread_active);
}
@@ -2277,6 +2294,60 @@ srv_shutdown_print_master_pending(
}
}
+#ifdef UNIV_DEBUG
+/** Waits in loop as long as master thread is disabled (debug) */
+static
+void
+srv_master_do_disabled_loop(void)
+{
+ if (!srv_master_thread_disabled_debug) {
+ /* We return here to avoid changing op_info. */
+ return;
+ }
+
+ srv_main_thread_op_info = "disabled";
+
+ while (srv_master_thread_disabled_debug) {
+ os_event_set(srv_master_thread_disabled_event);
+ if (srv_shutdown_state != SRV_SHUTDOWN_NONE) {
+ break;
+ }
+ os_thread_sleep(100000);
+ }
+
+ srv_main_thread_op_info = "";
+}
+
+/** Disables master thread. It's used by:
+ SET GLOBAL innodb_master_thread_disabled_debug = 1 (0).
+@param[in] thd thread handle
+@param[in] var pointer to system variable
+@param[out] var_ptr where the formal string goes
+@param[in] save immediate result from check function */
+void
+srv_master_thread_disabled_debug_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save)
+{
+ /* This method is protected by mutex, as every SET GLOBAL .. */
+ ut_ad(srv_master_thread_disabled_event != NULL);
+
+ const bool disable = *static_cast<const my_bool*>(save);
+
+ const int64_t sig_count = os_event_reset(
+ srv_master_thread_disabled_event);
+
+ srv_master_thread_disabled_debug = disable;
+
+ if (disable) {
+ os_event_wait_low(
+ srv_master_thread_disabled_event, sig_count);
+ }
+}
+#endif /* UNIV_DEBUG */
+
/*********************************************************************//**
Perform the tasks that the master thread is supposed to do when the
server is active. There are two types of tasks. The first category is
@@ -2307,6 +2378,8 @@ srv_master_do_active_tasks(void)
MONITOR_INC_TIME_IN_MICRO_SECS(
MONITOR_SRV_BACKGROUND_DROP_TABLE_MICROSECOND, counter_time);
+ ut_d(srv_master_do_disabled_loop());
+
if (srv_shutdown_state > 0) {
return;
}
@@ -2319,7 +2392,7 @@ srv_master_do_active_tasks(void)
/* Do an ibuf merge */
srv_main_thread_op_info = "doing insert buffer merge";
counter_time = ut_time_us(NULL);
- ibuf_merge_in_background(false, ULINT_UNDEFINED);
+ ibuf_merge_in_background(false);
MONITOR_INC_TIME_IN_MICRO_SECS(
MONITOR_SRV_IBUF_MERGE_MICROSECOND, counter_time);
@@ -2394,6 +2467,8 @@ srv_master_do_idle_tasks(void)
MONITOR_SRV_BACKGROUND_DROP_TABLE_MICROSECOND,
counter_time);
+ ut_d(srv_master_do_disabled_loop());
+
if (srv_shutdown_state > 0) {
return;
}
@@ -2406,7 +2481,7 @@ srv_master_do_idle_tasks(void)
/* Do an ibuf merge */
counter_time = ut_time_us(NULL);
srv_main_thread_op_info = "doing insert buffer merge";
- ibuf_merge_in_background(true, ULINT_UNDEFINED);
+ ibuf_merge_in_background(true);
MONITOR_INC_TIME_IN_MICRO_SECS(
MONITOR_SRV_IBUF_MERGE_MICROSECOND, counter_time);
@@ -2486,7 +2561,7 @@ srv_master_do_shutdown_tasks(
/* Do an ibuf merge */
srv_main_thread_op_info = "doing insert buffer merge";
- n_bytes_merged = ibuf_merge_in_background(true, ULINT_UNDEFINED);
+ n_bytes_merged = ibuf_merge_in_background(true);
/* Flush logs if needed */
srv_sync_log_buffer_in_background();
@@ -2600,7 +2675,7 @@ suspend_thread:
}
my_thread_end();
- os_thread_exit(NULL);
+ os_thread_exit();
DBUG_RETURN(0);
}
@@ -2741,7 +2816,7 @@ DECLARE_THREAD(srv_worker_thread)(
my_thread_end();
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN; /* Not reached, avoid compiler warning */
}
@@ -3015,6 +3090,12 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
n_pages_purged = trx_purge(1, srv_purge_batch_size, false);
}
+#ifdef UNIV_DEBUG
+ if (srv_fast_shutdown == 0) {
+ trx_commit_disallowed = true;
+ }
+#endif /* UNIV_DEBUG */
+
/* This trx_purge is called to remove any undo records (added by
background threads) after completion of the above loop. When
srv_fast_shutdown != 0, a large batch size can cause significant
@@ -3062,7 +3143,7 @@ DECLARE_THREAD(srv_purge_coordinator_thread)(
my_thread_end();
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN; /* Not reached, avoid compiler warning */
}
@@ -3145,17 +3226,24 @@ srv_is_tablespace_truncated(ulint space_id)
}
/** Check if tablespace was truncated.
-@param space_id space_id to check for truncate action
+@param[in] space space object to check for truncate action
@return true if tablespace was truncated and we still have an active
MLOG_TRUNCATE REDO log record. */
bool
-srv_was_tablespace_truncated(ulint space_id)
+srv_was_tablespace_truncated(const fil_space_t* space)
{
- if (is_system_tablespace(space_id)) {
+ if (space == NULL) {
+ ut_ad(0);
+ return(false);
+ }
+
+ bool has_shared_space = FSP_FLAGS_GET_SHARED(space->flags);
+
+ if (is_system_tablespace(space->id) || has_shared_space) {
return(false);
}
- return(truncate_t::was_tablespace_truncated(space_id));
+ return(truncate_t::was_tablespace_truncated(space->id));
}
/** Call exit(3) */
diff --git a/storage/innobase/srv/srv0start.cc b/storage/innobase/srv/srv0start.cc
index ab9150a2146..294431c8928 100644
--- a/storage/innobase/srv/srv0start.cc
+++ b/storage/innobase/srv/srv0start.cc
@@ -123,12 +123,6 @@ lsn_t srv_start_lsn;
/** Log sequence number at shutdown */
lsn_t srv_shutdown_lsn;
-#ifdef HAVE_DARWIN_THREADS
-# include <sys/utsname.h>
-/** TRUE if the F_FULLFSYNC option is available */
-UNIV_INTERN ibool srv_have_fullfsync = FALSE;
-#endif
-
/** TRUE if a raw partition is in use */
ibool srv_start_raw_disk_in_use = FALSE;
@@ -191,7 +185,6 @@ static bool thread_started[SRV_MAX_N_IO_THREADS + 6 + 32] = {false};
static bool buf_dump_thread_started = false;
static bool dict_stats_thread_started = false;
static bool buf_flush_page_cleaner_thread_started = false;
-
/** Name of srv_monitor_file */
static char* srv_monitor_file_name;
#endif /* !UNIV_HOTBACKUP */
@@ -219,6 +212,7 @@ mysql_pfs_key_t srv_lock_timeout_thread_key;
mysql_pfs_key_t srv_master_thread_key;
mysql_pfs_key_t srv_monitor_thread_key;
mysql_pfs_key_t srv_purge_thread_key;
+mysql_pfs_key_t srv_worker_thread_key;
#endif /* UNIV_PFS_THREAD */
#ifdef HAVE_PSI_STAGE_INTERFACE
@@ -345,7 +339,7 @@ DECLARE_THREAD(io_handler_thread)(
The thread actually never comes here because it is exited in an
os_event_wait(). */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -1474,32 +1468,6 @@ innobase_start_or_create_for_mysql(void)
srv_use_doublewrite_buf = FALSE;
}
-#ifdef HAVE_DARWIN_THREADS
-# ifdef F_FULLFSYNC
- /* This executable has been compiled on Mac OS X 10.3 or later.
- Assume that F_FULLFSYNC is available at run-time. */
- srv_have_fullfsync = TRUE;
-# else /* F_FULLFSYNC */
- /* This executable has been compiled on Mac OS X 10.2
- or earlier. Determine if the executable is running
- on Mac OS X 10.3 or later. */
- struct utsname utsname;
- if (uname(&utsname)) {
- ut_print_timestamp(stderr);
- fputs(" InnoDB: cannot determine Mac OS X version!\n", stderr);
- } else {
- srv_have_fullfsync = strcmp(utsname.release, "7.") >= 0;
- }
- if (!srv_have_fullfsync) {
- ut_print_timestamp(stderr);
- fputs(" InnoDB: On Mac OS X, fsync() may be "
- "broken on internal drives,\n", stderr);
- ut_print_timestamp(stderr);
- fputs(" InnoDB: making transactions unsafe!\n", stderr);
- }
-# endif /* F_FULLFSYNC */
-#endif /* HAVE_DARWIN_THREADS */
-
#ifdef HAVE_LZO1X
if (lzo_init() != LZO_E_OK) {
ib::warn() << "lzo_init() failed, support disabled";
@@ -1759,7 +1727,8 @@ innobase_start_or_create_for_mysql(void)
strlen(fil_path_to_mysql_datadir)
+ 20 + sizeof "/innodb_status."));
- sprintf(srv_monitor_file_name, "%s/innodb_status.%lu",
+ sprintf(srv_monitor_file_name,
+ "%s/innodb_status." ULINTPF,
fil_path_to_mysql_datadir,
os_proc_get_number());
@@ -1774,7 +1743,7 @@ innobase_start_or_create_for_mysql(void)
} else {
srv_monitor_file_name = NULL;
- srv_monitor_file = os_file_create_tmpfile();
+ srv_monitor_file = os_file_create_tmpfile(NULL);
if (!srv_monitor_file) {
return(srv_init_abort(DB_ERROR));
@@ -1784,7 +1753,7 @@ innobase_start_or_create_for_mysql(void)
mutex_create(LATCH_ID_SRV_DICT_TMPFILE,
&srv_dict_tmpfile_mutex);
- srv_dict_tmpfile = os_file_create_tmpfile();
+ srv_dict_tmpfile = os_file_create_tmpfile(NULL);
if (!srv_dict_tmpfile) {
return(srv_init_abort(DB_ERROR));
@@ -1793,7 +1762,7 @@ innobase_start_or_create_for_mysql(void)
mutex_create(LATCH_ID_SRV_MISC_TMPFILE,
&srv_misc_tmpfile_mutex);
- srv_misc_tmpfile = os_file_create_tmpfile();
+ srv_misc_tmpfile = os_file_create_tmpfile(NULL);
if (!srv_misc_tmpfile) {
return(srv_init_abort(DB_ERROR));
@@ -1899,6 +1868,8 @@ innobase_start_or_create_for_mysql(void)
os_thread_create(buf_flush_page_cleaner_coordinator,
NULL, NULL);
+ buf_flush_page_cleaner_thread_started = true;
+
for (i = 1; i < srv_n_page_cleaners; ++i) {
os_thread_create(buf_flush_page_cleaner_worker,
NULL, NULL);
@@ -2174,6 +2145,7 @@ files_checked:
trx_sys_create();
if (create_new_db) {
+ dberr_t err = DB_SUCCESS;
ut_a(!srv_read_only_mode);
@@ -2210,7 +2182,11 @@ files_checked:
flushed_lsn = log_get_lsn();
- fil_write_flushed_lsn(flushed_lsn);
+ err = fil_write_flushed_lsn(flushed_lsn);
+
+ if (err != DB_SUCCESS) {
+ return(srv_init_abort(err));
+ }
create_log_files_rename(
logfilename, dirnamelen, flushed_lsn, logfile0);
@@ -2366,6 +2342,17 @@ files_checked:
dict_check_tablespaces_and_store_max_id(validate);
}
+#ifdef MYSQL_ENCRYPTION
+ /* Rotate the encryption key for recovery. It's because
+ server could crash in middle of key rotation. Some tablespace
+ didn't complete key rotation. Here, we will resume the
+ rotation. */
+ if (!srv_read_only_mode
+ && srv_force_recovery < SRV_FORCE_NO_LOG_REDO) {
+ fil_encryption_rotate();
+ }
+#endif /* MYSQL_ENCRYPTION */
+
/* Fix-up truncate of table if server crashed while truncate
was active. */
err = truncate_t::fixup_tables_in_non_system_tablespace();
@@ -2378,6 +2365,7 @@ files_checked:
&& !recv_sys->found_corrupt_log
&& (srv_log_file_size_requested != srv_log_file_size
|| srv_n_log_files_found != srv_n_log_files)) {
+ dberr_t err = DB_SUCCESS;
/* Prepare to replace the redo log files. */
@@ -2399,7 +2387,11 @@ files_checked:
RECOVERY_CRASH(3);
/* Stamp the LSN to the data files. */
- fil_write_flushed_lsn(flushed_lsn);
+ err = fil_write_flushed_lsn(flushed_lsn);
+
+ if (err != DB_SUCCESS) {
+ return(srv_init_abort(err));
+ }
RECOVERY_CRASH(4);
@@ -2462,7 +2454,6 @@ files_checked:
if (err != DB_SUCCESS) {
return(srv_init_abort(err));
}
-
/* Create the doublewrite buffer to a new tablespace */
if (buf_dblwr == NULL && !buf_dblwr_create()) {
return(srv_init_abort(DB_ERROR));
@@ -2533,6 +2524,7 @@ files_checked:
return(srv_init_abort(err));
}
+ /* Create the SYS_TABLESPACES system table */
err = dict_create_or_check_sys_tablespace();
if (err != DB_SUCCESS) {
return(srv_init_abort(err));
@@ -2744,13 +2736,14 @@ files_checked:
}
}
+ /* Create the buffer pool resize thread */
+ os_thread_create(buf_resize_thread, NULL, NULL);
+
/* Init data for datafile scrub threads */
btr_scrub_init();
/* Initialize online defragmentation. */
btr_defragment_init();
- /* Create the buffer pool resize thread */
- os_thread_create(buf_resize_thread, NULL, NULL);
srv_was_started = TRUE;
return(DB_SUCCESS);
@@ -2803,10 +2796,8 @@ innobase_shutdown_for_mysql(void)
}
if (!srv_read_only_mode) {
- /* Shutdown the FTS optimize sub system. */
- fts_optimize_start_shutdown();
-
- fts_optimize_end();
+ fts_optimize_shutdown();
+ dict_stats_shutdown();
/* Shutdown key rotation threads */
fil_crypt_threads_end();
@@ -2828,13 +2819,10 @@ innobase_shutdown_for_mysql(void)
/* 2. Make all threads created by InnoDB to exit */
srv_shutdown_all_bg_threads();
-
- if (srv_use_mtflush) {
- /* g. Exit the multi threaded flush threads */
-
- buf_mtflu_io_thread_exit();
- }
-
+ if (srv_use_mtflush) {
+ /* g. Exit the multi threaded flush threads */
+ buf_mtflu_io_thread_exit();
+ }
if (srv_monitor_file) {
fclose(srv_monitor_file);
@@ -3042,10 +3030,9 @@ single-table tablespace.
@param[in] max_len filename max length */
void
srv_get_meta_data_filename(
-/*=======================*/
- dict_table_t* table, /*!< in: table */
- char* filename, /*!< out: filename */
- ulint max_len) /*!< in: filename max length */
+ dict_table_t* table,
+ char* filename,
+ ulint max_len)
{
ulint len;
char* path;
@@ -3070,3 +3057,36 @@ srv_get_meta_data_filename(
ut_free(path);
}
+/** Get the encryption-data filename from the table name for a
+single-table tablespace.
+@param[in] table table object
+@param[out] filename filename
+@param[in] max_len filename max length */
+void
+srv_get_encryption_data_filename(
+ dict_table_t* table,
+ char* filename,
+ ulint max_len)
+{
+ ulint len;
+ char* path;
+ /* Make sure the data_dir_path is set. */
+ dict_get_and_save_data_dir_path(table, false);
+
+ if (DICT_TF_HAS_DATA_DIR(table->flags)) {
+ ut_a(table->data_dir_path);
+
+ path = fil_make_filepath(
+ table->data_dir_path, table->name.m_name, CFP, true);
+ } else {
+ path = fil_make_filepath(NULL, table->name.m_name, CFP, false);
+ }
+
+ ut_a(path);
+ len = ut_strlen(path);
+ ut_a(max_len >= len);
+
+ strcpy(filename, path);
+
+ ut_free(path);
+}
diff --git a/storage/innobase/sync/sync0arr.cc b/storage/innobase/sync/sync0arr.cc
index e311023223c..f6416263eee 100644
--- a/storage/innobase/sync/sync0arr.cc
+++ b/storage/innobase/sync/sync0arr.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Copyright (c) 2013, 2015, MariaDB Corporation. All Rights Reserved.
@@ -530,9 +530,11 @@ sync_array_cell_print(
#endif /* UNIV_DEBUG */
if (mutex) {
- fprintf(file,
- "Mutex at %p created file %s line %lu, lock var %lu\n"
- "Last time reserved by thread %lu in file %s line %lu, "
+ fprintf(file,
+ "Mutex at %p, %s, lock var %lu\n"
+#ifdef UNIV_DEBUG
+ "Last time reserved in file %s line %lu"
+#endif /* UNIV_DEBUG */
"\n",
(void*) mutex,
policy.to_string().c_str(),
@@ -607,13 +609,13 @@ sync_array_cell_print(
" lock_word: %lx\n"
"Last time read locked in file %s line %lu\n"
"Last time write locked in file %s line %lu\n",
- (ulong) rw_lock_get_reader_count(rwlock),
- (ulong) rwlock->waiters,
+ (ulint) rw_lock_get_reader_count(rwlock),
+ (ulint) rwlock->waiters,
rwlock->lock_word,
innobase_basename(rwlock->last_s_file_name),
- (ulong) rwlock->last_s_line,
+ (ulint) rwlock->last_s_line,
rwlock->last_x_file_name,
- (ulong) rwlock->last_x_line);
+ (ulint) rwlock->last_x_line);
/* JAN: TODO: FIX LATER
fprintf(file,
@@ -735,7 +737,6 @@ sync_array_detect_deadlock(
os_thread_id_t thread;
ibool ret;
rw_lock_debug_t*debug;
- os_thread_id_t reserver=0;
ut_a(arr);
ut_a(start);
@@ -834,7 +835,6 @@ sync_array_detect_deadlock(
<< " file " << name << " line "
<< policy.get_enter_line();
- sync_array_cell_print(stderr, cell, 0);
return(true);
}
@@ -842,7 +842,8 @@ sync_array_detect_deadlock(
/* No deadlock */
return(false);
- }
+ }
+
case RW_LOCK_X:
case RW_LOCK_X_WAIT:
@@ -1133,7 +1134,7 @@ sync_array_print_long_waits_low(
# define SYNC_ARRAY_TIMEOUT 240
#endif
- for (i = 0; i < arr->n_cells; i++) {
+ for (ulint i = 0; i < arr->n_cells; i++) {
sync_cell_t* cell;
void* latch;
@@ -1301,7 +1302,6 @@ sync_array_print_info_low(
{
ulint i;
ulint count = 0;
- os_thread_id_t r = 0;
fprintf(file,
"OS WAIT ARRAY INFO: reservation count " ULINTPF "\n",
diff --git a/storage/innobase/sync/sync0debug.cc b/storage/innobase/sync/sync0debug.cc
index f7fcc8d9727..accc9313653 100644
--- a/storage/innobase/sync/sync0debug.cc
+++ b/storage/innobase/sync/sync0debug.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
Portions of this file contain modifications contributed and copyrighted by
Google, Inc. Those modifications are gratefully acknowledged and are described
@@ -485,6 +485,7 @@ LatchDebug::LatchDebug()
LEVEL_MAP_INSERT(SYNC_RECV);
LEVEL_MAP_INSERT(SYNC_LOG_FLUSH_ORDER);
LEVEL_MAP_INSERT(SYNC_LOG);
+ LEVEL_MAP_INSERT(SYNC_LOG_WRITE);
LEVEL_MAP_INSERT(SYNC_PAGE_CLEANER);
LEVEL_MAP_INSERT(SYNC_PURGE_QUEUE);
LEVEL_MAP_INSERT(SYNC_TRX_SYS_HEADER);
@@ -766,6 +767,7 @@ LatchDebug::check_order(
case SYNC_FTS_CACHE_INIT:
case SYNC_PAGE_CLEANER:
case SYNC_LOG:
+ case SYNC_LOG_WRITE:
case SYNC_LOG_FLUSH_ORDER:
case SYNC_FILE_FORMAT_TAG:
case SYNC_DOUBLEWRITE:
@@ -1389,6 +1391,8 @@ sync_latch_meta_init()
LATCH_ADD(LOG_SYS, SYNC_LOG, log_sys_mutex_key);
+ LATCH_ADD(LOG_WRITE, SYNC_LOG_WRITE, log_sys_write_mutex_key);
+
LATCH_ADD(LOG_FLUSH_ORDER, SYNC_LOG_FLUSH_ORDER,
log_flush_order_mutex_key);
@@ -1538,16 +1542,16 @@ sync_latch_meta_init()
LATCH_ADD(HASH_TABLE_RW_LOCK, SYNC_BUF_PAGE_HASH,
hash_table_locks_key);
-#ifdef UNIV_DEBUG
- LATCH_ADD(BUF_CHUNK_MAP_LATCH, SYNC_ANY_LATCH, buf_chunk_map_latch_key);
-#endif /* UNIV_DEBUG */
-
LATCH_ADD(SYNC_DEBUG_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
+ LATCH_ADD(MASTER_KEY_ID_MUTEX, SYNC_NO_ORDER_CHECK, master_key_id_mutex_key);
+
/* JAN: TODO: Add PFS instrumentation */
LATCH_ADD(SCRUB_STAT_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
LATCH_ADD(DEFRAGMENT_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
+ LATCH_ADD(BTR_DEFRAGMENT_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
LATCH_ADD(MTFLUSH_THREAD_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
+ LATCH_ADD(MTFLUSH_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
LATCH_ADD(FIL_CRYPT_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
LATCH_ADD(FIL_CRYPT_STAT_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
LATCH_ADD(FIL_CRYPT_DATA_MUTEX, SYNC_NO_ORDER_CHECK, PFS_NOT_INSTRUMENTED);
@@ -1565,6 +1569,7 @@ sync_latch_meta_init()
const latch_meta_t* meta = *it;
+
/* Skip blank entries */
if (meta == NULL || meta->get_id() == LATCH_ID_NONE) {
continue;
@@ -1803,6 +1808,6 @@ sync_check_close()
create_tracker = NULL;
- //sync_latch_meta_destroy();
+ // sync_latch_meta_destroy();
}
diff --git a/storage/innobase/sync/sync0rw.cc b/storage/innobase/sync/sync0rw.cc
index a3eb4254f28..7c8aad640a2 100644
--- a/storage/innobase/sync/sync0rw.cc
+++ b/storage/innobase/sync/sync0rw.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1995, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1995, 2016, Oracle and/or its affiliates. All Rights Reserved.
Copyright (c) 2008, Google Inc.
Portions of this file contain modifications contributed and copyrighted by
@@ -346,7 +346,7 @@ rw_lock_s_lock_spin(
ulint i = 0; /* spin round count */
sync_array_t* sync_arr;
ulint spin_count = 0;
- ulint count_os_wait = 0;
+ uint64_t count_os_wait = 0;
/* We reuse the thread id to index into the counter, cache
it here for efficiency. */
@@ -378,7 +378,8 @@ lock_loop:
if (rw_lock_s_lock_low(lock, pass, file_name, line)) {
if (count_os_wait > 0) {
- lock->count_os_wait += count_os_wait;
+ lock->count_os_wait +=
+ static_cast<uint32_t>(count_os_wait);
rw_lock_stats.rw_s_os_wait_count.add(count_os_wait);
}
@@ -409,7 +410,8 @@ lock_loop:
if (count_os_wait > 0) {
- lock->count_os_wait += count_os_wait;
+ lock->count_os_wait +=
+ static_cast<uint32_t>(count_os_wait);
rw_lock_stats.rw_s_os_wait_count.add(
count_os_wait);
@@ -476,13 +478,14 @@ rw_lock_x_lock_wait_func(
ulint i = 0;
ulint n_spins = 0;
sync_array_t* sync_arr;
- ulint count_os_wait = 0;
+ uint64_t count_os_wait = 0;
os_rmb;
ut_ad(lock->lock_word <= threshold);
while (lock->lock_word < threshold) {
+
HMT_low();
if (srv_spin_wait_delay) {
ut_delay(ut_rnd_interval(0, srv_spin_wait_delay));
@@ -544,6 +547,14 @@ rw_lock_x_lock_wait_func(
lock->count_os_wait += count_os_wait;
rw_lock_stats.rw_x_os_wait_count.add(count_os_wait);
}
+
+ rw_lock_stats.rw_x_spin_round_count.add(n_spins);
+
+ if (count_os_wait > 0) {
+ lock->count_os_wait +=
+ static_cast<uint32_t>(count_os_wait);
+ rw_lock_stats.rw_x_os_wait_count.add(count_os_wait);
+ }
}
#ifdef UNIV_DEBUG
@@ -589,11 +600,7 @@ rw_lock_x_lock_low(
os_rmb;
}
- /* Decrement failed: relock or failed lock
- Note: recursive must be loaded before writer_thread see
- comment for rw_lock_set_writer_id_and_recursion_flag().
- To achieve this we load it before rw_lock_lock_word_decr(),
- An X or SX lock is held by either
+ /* Decrement failed: An X or SX lock is held by either
this thread or another. Try to relock. */
if (!pass
&& lock->recursive
@@ -671,7 +678,6 @@ rw_lock_sx_lock_low(
lock, !pass);
lock->sx_recursive = 1;
-
} else {
os_thread_id_t thread_id = os_thread_get_curr_id();
@@ -747,7 +753,7 @@ rw_lock_x_lock_func(
ulint i = 0;
sync_array_t* sync_arr;
ulint spin_count = 0;
- ulint count_os_wait = 0;
+ uint64_t count_os_wait = 0;
ut_ad(rw_lock_validate(lock));
ut_ad(!rw_lock_own(lock, RW_LOCK_S));
@@ -757,7 +763,8 @@ lock_loop:
if (rw_lock_x_lock_low(lock, pass, file_name, line)) {
if (count_os_wait > 0) {
- lock->count_os_wait += count_os_wait;
+ lock->count_os_wait +=
+ static_cast<uint32_t>(count_os_wait);
rw_lock_stats.rw_x_os_wait_count.add(count_os_wait);
}
@@ -809,7 +816,8 @@ lock_loop:
sync_array_free_cell(sync_arr, cell);
if (count_os_wait > 0) {
- lock->count_os_wait += count_os_wait;
+ lock->count_os_wait +=
+ static_cast<uint32_t>(count_os_wait);
rw_lock_stats.rw_x_os_wait_count.add(count_os_wait);
}
@@ -850,7 +858,7 @@ rw_lock_sx_lock_func(
ulint i = 0;
sync_array_t* sync_arr;
ulint spin_count = 0;
- ulint count_os_wait = 0;
+ uint64_t count_os_wait = 0;
ulint spin_wait_count = 0;
ut_ad(rw_lock_validate(lock));
@@ -861,7 +869,8 @@ lock_loop:
if (rw_lock_sx_lock_low(lock, pass, file_name, line)) {
if (count_os_wait > 0) {
- lock->count_os_wait += count_os_wait;
+ lock->count_os_wait +=
+ static_cast<uint32_t>(count_os_wait);
rw_lock_stats.rw_sx_os_wait_count.add(count_os_wait);
}
@@ -914,7 +923,8 @@ lock_loop:
sync_array_free_cell(sync_arr, cell);
if (count_os_wait > 0) {
- lock->count_os_wait += count_os_wait;
+ lock->count_os_wait +=
+ static_cast<uint32_t>(count_os_wait);
rw_lock_stats.rw_sx_os_wait_count.add(count_os_wait);
}
@@ -1249,7 +1259,7 @@ rw_lock_list_print_info(
#endif /* INNODB_RW_LOCKS_USE_ATOMICS */
}
- fprintf(file, "Total number of rw-locks %ld\n", count);
+ fprintf(file, "Total number of rw-locks " ULINTPF "\n", count);
mutex_exit(&rw_lock_list_mutex);
}
diff --git a/storage/innobase/sync/sync0sync.cc b/storage/innobase/sync/sync0sync.cc
index f304d7dbe15..9aba075caa6 100644
--- a/storage/innobase/sync/sync0sync.cc
+++ b/storage/innobase/sync/sync0sync.cc
@@ -56,6 +56,7 @@ mysql_pfs_key_t ibuf_bitmap_mutex_key;
mysql_pfs_key_t ibuf_mutex_key;
mysql_pfs_key_t ibuf_pessimistic_insert_mutex_key;
mysql_pfs_key_t log_sys_mutex_key;
+mysql_pfs_key_t log_sys_write_mutex_key;
mysql_pfs_key_t log_cmdq_mutex_key;
mysql_pfs_key_t log_flush_order_mutex_key;
mysql_pfs_key_t mutex_list_mutex_key;
@@ -68,6 +69,7 @@ mysql_pfs_key_t redo_rseg_mutex_key;
mysql_pfs_key_t noredo_rseg_mutex_key;
mysql_pfs_key_t page_zip_stat_per_index_mutex_key;
# ifdef UNIV_DEBUG
+mysql_pfs_key_t sync_thread_mutex_key;
mysql_pfs_key_t rw_lock_debug_mutex_key;
# endif /* UNIV_DEBUG */
mysql_pfs_key_t rtr_active_mutex_key;
@@ -80,9 +82,6 @@ mysql_pfs_key_t srv_dict_tmpfile_mutex_key;
mysql_pfs_key_t srv_innodb_monitor_mutex_key;
mysql_pfs_key_t srv_misc_tmpfile_mutex_key;
mysql_pfs_key_t srv_monitor_file_mutex_key;
-# ifdef UNIV_DEBUG
-mysql_pfs_key_t sync_thread_mutex_key;
-# endif /* UNIV_DEBUG */
mysql_pfs_key_t buf_dblwr_mutex_key;
mysql_pfs_key_t trx_undo_mutex_key;
mysql_pfs_key_t trx_mutex_key;
@@ -99,8 +98,8 @@ mysql_pfs_key_t sync_array_mutex_key;
mysql_pfs_key_t thread_mutex_key;
mysql_pfs_key_t zip_pad_mutex_key;
mysql_pfs_key_t row_drop_list_mutex_key;
+mysql_pfs_key_t master_key_id_mutex_key;
#endif /* UNIV_PFS_MUTEX */
-
#ifdef UNIV_PFS_RWLOCK
mysql_pfs_key_t btr_search_latch_key;
mysql_pfs_key_t buf_block_lock_key;
@@ -118,9 +117,6 @@ mysql_pfs_key_t fts_cache_rw_lock_key;
mysql_pfs_key_t fts_cache_init_rw_lock_key;
mysql_pfs_key_t trx_i_s_cache_lock_key;
mysql_pfs_key_t trx_purge_latch_key;
-# ifdef UNIV_DEBUG
-mysql_pfs_key_t buf_chunk_map_latch_key;
-# endif /* UNIV_DEBUG */
#endif /* UNIV_PFS_RWLOCK */
/** For monitoring active mutexes */
diff --git a/storage/innobase/trx/trx0i_s.cc b/storage/innobase/trx/trx0i_s.cc
index 4fb214a89c4..cf3109c265e 100644
--- a/storage/innobase/trx/trx0i_s.cc
+++ b/storage/innobase/trx/trx0i_s.cc
@@ -715,7 +715,6 @@ fill_lock_data(
page = reinterpret_cast<const page_t*>(buf_block_get_frame(block));
-
rec_offs_init(offsets_onstack);
offsets = offsets_onstack;
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index 06da23d0a90..7cf8c38bb8e 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -65,6 +65,7 @@ trx_undo_rec_t trx_purge_dummy_rec;
#ifdef UNIV_DEBUG
my_bool srv_purge_view_update_only_debug;
+bool trx_commit_disallowed = false;
#endif /* UNIV_DEBUG */
/** Sentinel value */
@@ -198,7 +199,7 @@ trx_purge_graph_build(
for (i = 0; i < n_purge_threads; ++i) {
que_thr_t* thr;
- thr = que_thr_create(fork, heap);
+ thr = que_thr_create(fork, heap, NULL);
thr->child = row_purge_node_create(thr, heap);
}
@@ -364,6 +365,8 @@ trx_purge_add_update_undo_to_history(
hist_size + undo->size, MLOG_4BYTES, mtr);
}
+ ut_ad(!trx_commit_disallowed);
+
/* Add the log as the first in the history list */
flst_add_first(rseg_header + TRX_RSEG_HISTORY,
undo_header + TRX_UNDO_HISTORY_NODE, mtr);
@@ -551,7 +554,11 @@ loop:
if (undo_trx_no >= limit->trx_no) {
- if (undo_trx_no == limit->trx_no) {
+ /* limit space_id should match the rollback segment
+ space id to avoid freeing of the page belongs to
+ different rollback segment for the same trx_no. */
+ if (undo_trx_no == limit->trx_no
+ && rseg->space == limit->undo_rseg_space) {
trx_undo_truncate_start(
rseg, hdr_addr.page,
@@ -1548,7 +1555,7 @@ Fetches the next undo log record from the history list to purge. It must be
released with the corresponding release function.
@return copy of an undo log record or pointer to trx_purge_dummy_rec,
if the whole undo log can skipped in purge; NULL if none left */
-static MY_ATTRIBUTE((warn_unused_result, nonnull))
+static MY_ATTRIBUTE((warn_unused_result))
trx_undo_rec_t*
trx_purge_fetch_next_rec(
/*=====================*/
diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc
index 6371eeefbdc..b99ce22823b 100644
--- a/storage/innobase/trx/trx0rec.cc
+++ b/storage/innobase/trx/trx0rec.cc
@@ -262,7 +262,8 @@ trx_undo_log_v_idx(
it != vcol->v_indexes->end(); ++it) {
dict_v_idx_t v_index = *it;
- ptr += mach_write_compressed(ptr, v_index.index->id);
+ ptr += mach_write_compressed(
+ ptr, static_cast<ulint>(v_index.index->id));
ptr += mach_write_compressed(ptr, v_index.nth_field);
}
@@ -305,10 +306,10 @@ trx_undo_read_v_idx_low(
dict_index_t* index = dict_table_get_next_index(clust_index);
while (index != NULL) {
- /* Return when we find an index matches the id.
- TODO: in the future, it might worth to add more
- check with other indexes */
- if (index->id == id && index->is_committed()) {
+ /* Return if we find a matching index.
+ TODO: in the future, it might be worth to add
+ checks on other indexes */
+ if (index->id == id) {
const dict_col_t* col = dict_index_get_nth_col(
index, pos);
ut_ad(dict_col_is_virtual(col));
@@ -332,6 +333,11 @@ still indexed, and output its position
@param[in] ptr undo log pointer
@param[in] first_v_col if this is the first virtual column, which
has the version marker
+@param[in,out] is_undo_log this function is used to parse both undo log,
+ and online log for virtual columns. So
+ check to see if this is undo log. When
+ first_v_col is true, is_undo_log is output,
+ when first_v_col is false, is_undo_log is input
@param[in,out] field_no the column number
@return remaining part of undo log record after reading these values */
const byte*
@@ -339,24 +345,21 @@ trx_undo_read_v_idx(
const dict_table_t* table,
const byte* ptr,
bool first_v_col,
+ bool* is_undo_log,
ulint* field_no)
{
- /* this function is used to parse both undo log, and online log
- for virtual columns. So check to see if this is undo log */
- bool is_undo_log = true;
-
/* Version marker only put on the first virtual column */
if (first_v_col) {
/* Undo log has the virtual undo log marker */
- is_undo_log = (mach_read_from_1(ptr)
- == VIRTUAL_COL_UNDO_FORMAT_1);
+ *is_undo_log = (mach_read_from_1(ptr)
+ == VIRTUAL_COL_UNDO_FORMAT_1);
- if (is_undo_log) {
+ if (*is_undo_log) {
ptr += 1;
}
}
- if (is_undo_log) {
+ if (*is_undo_log) {
ptr = trx_undo_read_v_idx_low(table, ptr, field_no);
} else {
*field_no -= REC_MAX_N_FIELDS;
@@ -382,6 +385,10 @@ trx_undo_report_insert_virtual(
byte* start = *ptr;
bool first_v_col = true;
+ if (trx_undo_left(undo_page, *ptr) < 2) {
+ return(false);
+ }
+
/* Reserve 2 bytes to write the number
of bytes the stored fields take in this
undo record */
@@ -434,6 +441,11 @@ trx_undo_report_insert_virtual(
ut_memcpy(*ptr, vfield->data, flen);
*ptr += flen;
} else {
+ if (trx_undo_left(undo_page, *ptr) < 5) {
+
+ return(false);
+ }
+
*ptr += mach_write_compressed(*ptr, flen);
}
}
@@ -585,7 +597,7 @@ trx_undo_rec_get_col_val(
*orig_len = mach_read_next_compressed(&ptr);
*len = mach_read_next_compressed(&ptr);
*field = ptr;
- ptr += *len;
+ ptr += *len & ~SPATIAL_STATUS_MASK;
ut_ad(*orig_len >= BTR_EXTERN_FIELD_REF_SIZE);
ut_ad(*len > *orig_len);
@@ -603,7 +615,8 @@ trx_undo_rec_get_col_val(
default:
*field = ptr;
if (*len >= UNIV_EXTERN_STORAGE_FIELD) {
- ptr += *len - UNIV_EXTERN_STORAGE_FIELD;
+ ptr += (*len - UNIV_EXTERN_STORAGE_FIELD)
+ & ~SPATIAL_STATUS_MASK;
} else {
ptr += *len;
}
@@ -721,13 +734,14 @@ trx_undo_page_fetch_ext(
@param[out] ptr undo log position, at least 15 bytes must be
available
@param[out] ext_buf a buffer of DICT_MAX_FIELD_LEN_BY_FORMAT()
-size, or NULL when should not fetch a longer prefix
+ size, or NULL when should not fetch a longer
+ prefix
@param[in] prefix_len prefix size to store in the undo log
@param[in] page_size page size
@param[in,out] field the locally stored part of the externally
stored column
@param[in,out] len length of field, in bytes
-@param[in] spatial_statis whether the column is used by spatial index or
+@param[in] spatial_status whether the column is used by spatial index or
regular index
@return undo log position */
static
@@ -739,21 +753,25 @@ trx_undo_page_report_modify_ext(
const page_size_t& page_size,
const byte** field,
ulint* len,
- col_spatial_status spatial_status)
+ spatial_status_t spatial_status)
{
ulint spatial_len= 0;
switch (spatial_status) {
+ case SPATIAL_UNKNOWN:
case SPATIAL_NONE:
break;
case SPATIAL_MIXED:
+ case SPATIAL_ONLY:
spatial_len = DATA_MBR_LEN;
break;
+ }
- case SPATIAL_ONLY:
- spatial_len = DATA_MBR_LEN;
+ /* Encode spatial status into length. */
+ spatial_len |= spatial_status << SPATIAL_STATUS_SHIFT;
+ if (spatial_status == SPATIAL_ONLY) {
/* If the column is only used by gis index, log its
MBR is enough.*/
ptr += mach_write_compressed(ptr, UNIV_EXTERN_STORAGE_FIELD
@@ -983,7 +1001,31 @@ trx_undo_page_report_modify(
return(0);
}
- ptr += mach_write_compressed(ptr, upd_get_n_fields(update));
+ ulint n_updated = upd_get_n_fields(update);
+
+ /* If this is an online update while an inplace alter table
+ is in progress and the table has virtual column, we will
+ need to double check if there are any non-indexed columns
+ being registered in update vector in case they will be indexed
+ in new table */
+ if (dict_index_is_online_ddl(index)
+ && index->table->n_v_cols > 0) {
+ for (i = 0; i < upd_get_n_fields(update); i++) {
+ upd_field_t* fld = upd_get_nth_field(
+ update, i);
+ ulint pos = fld->field_no;
+
+ /* These columns must not have an index
+ on them */
+ if (upd_fld_is_virtual_col(fld)
+ && dict_table_get_nth_v_col(
+ table, pos)->v_indexes->empty()) {
+ n_updated--;
+ }
+ }
+ }
+
+ ptr += mach_write_compressed(ptr, n_updated);
for (i = 0; i < upd_get_n_fields(update); i++) {
upd_field_t* fld = upd_get_nth_field(update, i);
@@ -999,8 +1041,17 @@ trx_undo_page_report_modify(
return(0);
}
- /* add REC_MAX_N_FIELDS to mark this is a virtaul col */
if (is_virtual) {
+ /* Skip the non-indexed column, during
+ an online alter table */
+ if (dict_index_is_online_ddl(index)
+ && dict_table_get_nth_v_col(
+ table, pos)->v_indexes->empty()) {
+ continue;
+ }
+
+ /* add REC_MAX_N_FIELDS to mark this
+ is a virtual col */
pos += REC_MAX_N_FIELDS;
}
@@ -1059,7 +1110,7 @@ trx_undo_page_report_modify(
&& flen < REC_ANTELOPE_MAX_INDEX_COL_LEN
? ext_buf : NULL, prefix_len,
dict_table_page_size(table),
- &field, &flen, SPATIAL_NONE);
+ &field, &flen, SPATIAL_UNKNOWN);
/* Notify purge that it eventually has to
free the old externally stored field */
@@ -1155,7 +1206,7 @@ trx_undo_page_report_modify(
if (col->ord_part) {
ulint pos;
- col_spatial_status spatial_status;
+ spatial_status_t spatial_status;
spatial_status = SPATIAL_NONE;
@@ -1286,10 +1337,15 @@ trx_undo_page_report_modify(
return(0);
}
- if (update && update->old_vrow) {
+ if (update) {
ut_ad(!row);
- vfield = dtuple_get_nth_v_field(
- update->old_vrow, col->v_pos);
+ if (update->old_vrow == NULL) {
+ flen = UNIV_SQL_NULL;
+ } else {
+ vfield = dtuple_get_nth_v_field(
+ update->old_vrow,
+ col->v_pos);
+ }
} else if (row) {
vfield = dtuple_get_nth_v_field(
row, col->v_pos);
@@ -1297,8 +1353,12 @@ trx_undo_page_report_modify(
ut_ad(0);
}
- field = static_cast<byte*>(vfield->data);
- flen = vfield->len;
+ if (vfield) {
+ field = static_cast<byte*>(vfield->data);
+ flen = vfield->len;
+ } else {
+ ut_ad(flen == UNIV_SQL_NULL);
+ }
if (flen != UNIV_SQL_NULL) {
flen = ut_min(
@@ -1407,6 +1467,7 @@ trx_undo_update_rec_get_update(
byte* buf;
ulint i;
bool first_v_col = true;
+ bool is_undo_log = true;
ulint n_skip_field = 0;
ut_a(dict_index_is_clust(index));
@@ -1463,18 +1524,19 @@ trx_undo_update_rec_get_update(
/* If new version, we need to check index list to figure
out the correct virtual column position */
ptr = trx_undo_read_v_idx(
- index->table, ptr, first_v_col, &field_no);
+ index->table, ptr, first_v_col, &is_undo_log,
+ &field_no);
first_v_col = false;
} else if (field_no >= dict_index_get_n_fields(index)) {
ib::error() << "Trying to access update undo rec"
" field " << field_no
<< " in index " << index->name
- << " of table " << index->table->name.m_name
+ << " of table " << index->table->name
<< " but index has only "
<< dict_index_get_n_fields(index)
<< " fields " << BUG_REPORT_MSG
<< ". Run also CHECK TABLE "
- << index->table->name.m_name << "."
+ << index->table->name << "."
" n_fields = " << n_fields << ", i = " << i
<< ", ptr " << ptr;
@@ -1592,6 +1654,7 @@ trx_undo_rec_get_partial_row(
{
const byte* end_ptr;
bool first_v_col = true;
+ bool is_undo_log = true;
ut_ad(index);
ut_ad(ptr);
@@ -1631,7 +1694,8 @@ trx_undo_rec_get_partial_row(
if (is_virtual) {
ptr = trx_undo_read_v_idx(
- index->table, ptr, first_v_col, &field_no);
+ index->table, ptr, first_v_col, &is_undo_log,
+ &field_no);
first_v_col = false;
}
@@ -1665,8 +1729,19 @@ trx_undo_rec_get_partial_row(
if (len != UNIV_SQL_NULL
&& len >= UNIV_EXTERN_STORAGE_FIELD) {
- col_spatial_status spatial_status;
- spatial_status = dict_col_get_spatial_status(col);
+ spatial_status_t spatial_status;
+
+ /* Decode spatial status. */
+ spatial_status = static_cast<spatial_status_t>(
+ (len & SPATIAL_STATUS_MASK)
+ >> SPATIAL_STATUS_SHIFT);
+ len &= ~SPATIAL_STATUS_MASK;
+
+ /* Keep compatible with 5.7.9 format. */
+ if (spatial_status == SPATIAL_UNKNOWN) {
+ spatial_status =
+ dict_col_get_spatial_status(col);
+ }
switch (spatial_status) {
case SPATIAL_ONLY:
@@ -1689,9 +1764,15 @@ trx_undo_rec_get_partial_row(
dfield,
len - UNIV_EXTERN_STORAGE_FIELD);
break;
+
+ case SPATIAL_UNKNOWN:
+ ut_ad(0);
+ break;
}
dfield_set_ext(dfield);
+ dfield_set_spatial_status(dfield, spatial_status);
+
/* If the prefix of this column is indexed,
ensure that enough prefix is stored in the
undo log record. */
@@ -2075,7 +2156,7 @@ Copies an undo record to heap.
truncated and we cannot fetch the old version
@retval false if the undo log record is available
NOTE: the caller must have latches on the clustered index page. */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
bool
trx_undo_get_undo_rec(
/*==================*/
@@ -2316,8 +2397,7 @@ trx_undo_prev_version_build(
*old_vers, index, NULL, ULINT_UNDEFINED, &heap)));
#endif // defined UNIV_DEBUG || defined UNIV_BLOB_LIGHT_DEBUG
- if (vrow && type != TRX_UNDO_DEL_MARK_REC
- && !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
+ if (vrow && !(cmpl_info & UPD_NODE_NO_ORD_CHANGE)) {
if (!(*vrow)) {
*vrow = dtuple_create_with_vcol(
v_heap ? v_heap : heap,
@@ -2331,6 +2411,7 @@ trx_undo_prev_version_build(
v_status & TRX_UNDO_PREV_IN_PURGE, NULL);
}
+
return(true);
}
@@ -2350,6 +2431,7 @@ trx_undo_read_v_cols(
{
const byte* end_ptr;
bool first_v_col = true;
+ bool is_undo_log = true;
end_ptr = ptr + mach_read_from_2(ptr);
ptr += 2;
@@ -2368,7 +2450,8 @@ trx_undo_read_v_cols(
if (is_virtual) {
ptr = trx_undo_read_v_idx(
- table, ptr, first_v_col, &field_no);
+ table, ptr, first_v_col, &is_undo_log,
+ &field_no);
first_v_col = false;
}
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index 3e431b146a7..7071b53fffe 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -110,7 +110,7 @@ trx_rollback_to_savepoint_low(
ut_ad(trx->rsegs.m_redo.rseg != 0
|| trx->rsegs.m_noredo.rseg != 0);
- thr = pars_complete_graph_for_exec(roll_node, trx, heap);
+ thr = pars_complete_graph_for_exec(roll_node, trx, heap, NULL);
ut_a(thr == que_fork_start_command(
static_cast<que_fork_t*>(que_node_get_parent(thr))));
@@ -207,8 +207,7 @@ trx_rollback_low(
case TRX_STATE_NOT_STARTED:
trx->will_lock = 0;
ut_ad(trx->in_mysql_trx_list);
- return(trx->state == TRX_STATE_NOT_STARTED
- ? DB_SUCCESS : DB_FORCED_ABORT);
+ return(DB_SUCCESS);
case TRX_STATE_ACTIVE:
ut_ad(trx->in_mysql_trx_list);
@@ -290,11 +289,6 @@ trx_rollback_for_mysql(
TrxInInnoDB trx_in_innodb(trx, true);
- if (trx_in_innodb.is_aborted()) {
-
- return(DB_FORCED_ABORT);
- }
-
return(trx_rollback_low(trx));
}
}
@@ -317,8 +311,6 @@ trx_rollback_last_sql_stat_for_mysql(
switch (trx->state) {
case TRX_STATE_FORCED_ROLLBACK:
- return(DB_FORCED_ABORT);
-
case TRX_STATE_NOT_STARTED:
return(DB_SUCCESS);
@@ -651,7 +643,7 @@ trx_rollback_active(
fork = que_fork_create(NULL, NULL, QUE_FORK_RECOVERY, heap);
fork->trx = trx;
- thr = que_thr_create(fork, heap);
+ thr = que_thr_create(fork, heap, NULL);
roll_node = roll_node_create(heap);
@@ -887,7 +879,7 @@ DECLARE_THREAD(trx_rollback_or_clean_all_recovered)(
/* We count the number of threads in os_thread_exit(). A created
thread should always use that to exit and not use return() to exit. */
- os_thread_exit(NULL);
+ os_thread_exit();
OS_THREAD_DUMMY_RETURN;
}
@@ -1120,7 +1112,7 @@ trx_roll_graph_build(
fork = que_fork_create(NULL, NULL, QUE_FORK_ROLLBACK, heap);
fork->trx = trx;
- thr = que_thr_create(fork, heap);
+ thr = que_thr_create(fork, heap, NULL);
thr->child = row_undo_node_create(trx, thr, heap);
diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc
index 125bd2aec62..d5520b783b1 100644
--- a/storage/innobase/trx/trx0rseg.cc
+++ b/storage/innobase/trx/trx0rseg.cc
@@ -319,15 +319,19 @@ static
void
trx_rseg_create_instance(
/*=====================*/
- trx_sysf_t* sys_header, /*!< in: trx system header */
- purge_pq_t* purge_queue, /*!< in/out: rseg queue */
- mtr_t* mtr) /*!< in: mtr */
+ purge_pq_t* purge_queue) /*!< in/out: rseg queue */
{
ulint i;
for (i = 0; i < TRX_SYS_N_RSEGS; i++) {
ulint page_no;
+ mtr_t mtr;
+ mtr.start();
+ trx_sysf_t* sys_header = trx_sysf_get(&mtr);
+
+ page_no = trx_sysf_rseg_get_page_no(sys_header, i, &mtr);
+
/* Slot-1....Slot-n are reserved for non-redo rsegs.
Non-redo rsegs are recreated on server re-start so
avoid initializing the existing non-redo rsegs. */
@@ -337,20 +341,15 @@ trx_rseg_create_instance(
in range from slot-1....slot-n needs to be scheduled
for purge if there are pending purge operation. */
trx_rseg_schedule_pending_purge(
- sys_header, purge_queue, i, mtr);
+ sys_header, purge_queue, i, &mtr);
- continue;
- }
-
- page_no = trx_sysf_rseg_get_page_no(sys_header, i, mtr);
-
- if (page_no != FIL_NULL) {
+ } else if (page_no != FIL_NULL) {
ulint space;
trx_rseg_t* rseg = NULL;
ut_a(!trx_rseg_get_on_id(i, true));
- space = trx_sysf_rseg_get_space(sys_header, i, mtr);
+ space = trx_sysf_rseg_get_space(sys_header, i, &mtr);
bool found = true;
const page_size_t& page_size
@@ -365,12 +364,13 @@ trx_rseg_create_instance(
rseg = trx_rseg_mem_create(
i, space, page_no, page_size,
- purge_queue, rseg_array, mtr);
+ purge_queue, rseg_array, &mtr);
ut_a(rseg->id == i);
} else {
ut_a(trx_sys->rseg_array[i] == NULL);
}
+ mtr.commit();
}
}
@@ -447,13 +447,11 @@ rseg array in trx_sys at a database startup. */
void
trx_rseg_array_init(
/*================*/
- trx_sysf_t* sys_header, /* in/out: trx system header */
- purge_pq_t* purge_queue, /*!< in: rseg queue */
- mtr_t* mtr) /*!< in: mtr */
+ purge_pq_t* purge_queue) /*!< in: rseg queue */
{
trx_sys->rseg_history_len = 0;
- trx_rseg_create_instance(sys_header, purge_queue, mtr);
+ trx_rseg_create_instance(purge_queue);
}
/********************************************************************
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index 7537ef2e445..a253ea72e95 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -186,9 +186,9 @@ trx_sys_flush_max_trx_id(void)
trx_sysf_t* sys_header;
#ifndef WITH_WSREP
- /* wsrep_fake_trx_id violates this assert
- * Copied from trx_sys_get_new_trx_id
- */
+ /* wsrep_fake_trx_id violates this assert
+ Copied from trx_sys_get_new_trx_id
+ */
ut_ad(trx_sys_mutex_own());
#endif /* WITH_WSREP */
@@ -217,14 +217,10 @@ trx_sys_update_mysql_binlog_offset(
int64_t offset, /*!< in: position in that log file */
ulint field, /*!< in: offset of the MySQL log info field in
the trx sys header */
-#ifdef WITH_WSREP
trx_sysf_t* sys_header, /*!< in: trx sys header */
-#endif /* WITH_WSREP */
mtr_t* mtr) /*!< in: mtr */
{
-#ifndef WITH_WSREP
- trx_sysf_t* sys_header;
-#endif /* !WITH_WSREP */
+ DBUG_PRINT("InnoDB",("trx_mysql_binlog_offset: %lld", (longlong) offset));
if (ut_strlen(file_name) >= TRX_SYS_MYSQL_LOG_NAME_LEN) {
@@ -233,9 +229,9 @@ trx_sys_update_mysql_binlog_offset(
return;
}
-#ifndef WITH_WSREP
- sys_header = trx_sysf_get(mtr);
-#endif /* !WITH_WSREP */
+ if (sys_header == NULL) {
+ sys_header = trx_sysf_get(mtr);
+ }
if (mach_read_from_4(sys_header + field
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
@@ -322,119 +318,119 @@ static unsigned char trx_sys_cur_xid_uuid[16];
long long read_wsrep_xid_seqno(const XID* xid)
{
- long long seqno;
- memcpy(&seqno, xid->data + 24, sizeof(long long));
- return seqno;
+ long long seqno;
+ memcpy(&seqno, xid->data + 24, sizeof(long long));
+ return seqno;
}
void read_wsrep_xid_uuid(const XID* xid, unsigned char* buf)
{
- memcpy(buf, xid->data + 8, 16);
+ memcpy(buf, xid->data + 8, 16);
}
#endif /* UNIV_DEBUG */
void
trx_sys_update_wsrep_checkpoint(
- const XID* xid, /*!< in: transaction XID */
- trx_sysf_t* sys_header, /*!< in: sys_header */
- mtr_t* mtr) /*!< in: mtr */
+/*============================*/
+ const XID* xid, /*!< in: transaction XID */
+ trx_sysf_t* sys_header, /*!< in: sys_header */
+ mtr_t* mtr) /*!< in: mtr */
{
#ifdef UNIV_DEBUG
- {
- /* Check that seqno is monotonically increasing */
- unsigned char xid_uuid[16];
- long long xid_seqno = read_wsrep_xid_seqno(xid);
- read_wsrep_xid_uuid(xid, xid_uuid);
- if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 16))
- {
- /*
- This check is a protection against the initial seqno (-1)
- assigned in read_wsrep_xid_uuid(), which, if not checked,
- would cause the following assertion to fail.
- */
- if (xid_seqno > -1 )
- {
- ut_ad(xid_seqno > trx_sys_cur_xid_seqno);
- }
- }
- else
- {
- memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16);
- }
- trx_sys_cur_xid_seqno = xid_seqno;
- }
+ {
+ /* Check that seqno is monotonically increasing */
+ unsigned char xid_uuid[16];
+ long long xid_seqno = read_wsrep_xid_seqno(xid);
+ read_wsrep_xid_uuid(xid, xid_uuid);
+ if (!memcmp(xid_uuid, trx_sys_cur_xid_uuid, 16))
+ {
+ /*
+ This check is a protection against the initial seqno (-1)
+ assigned in read_wsrep_xid_uuid(), which, if not checked,
+ would cause the following assertion to fail.
+ */
+ if (xid_seqno > -1 )
+ {
+ ut_ad(xid_seqno > trx_sys_cur_xid_seqno);
+ }
+ } else {
+ memcpy(trx_sys_cur_xid_uuid, xid_uuid, 16);
+ }
+ trx_sys_cur_xid_seqno = xid_seqno;
+ }
#endif /* UNIV_DEBUG */
- ut_ad(xid && mtr);
- ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid));
-
- if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
- + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
- != TRX_SYS_WSREP_XID_MAGIC_N) {
- mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
- + TRX_SYS_WSREP_XID_MAGIC_N_FLD,
- TRX_SYS_WSREP_XID_MAGIC_N,
- MLOG_4BYTES, mtr);
- }
-
- mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
- + TRX_SYS_WSREP_XID_FORMAT,
- (int)xid->formatID,
- MLOG_4BYTES, mtr);
- mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
- + TRX_SYS_WSREP_XID_GTRID_LEN,
- (int)xid->gtrid_length,
- MLOG_4BYTES, mtr);
- mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
- + TRX_SYS_WSREP_XID_BQUAL_LEN,
- (int)xid->bqual_length,
- MLOG_4BYTES, mtr);
- mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO
- + TRX_SYS_WSREP_XID_DATA,
- (const unsigned char*) xid->data,
- XIDDATASIZE, mtr);
+ ut_ad(xid && mtr);
+ ut_a(xid->formatID == -1 || wsrep_is_wsrep_xid(xid));
+
+ if (mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD)
+ != TRX_SYS_WSREP_XID_MAGIC_N) {
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD,
+ TRX_SYS_WSREP_XID_MAGIC_N,
+ MLOG_4BYTES, mtr);
+ }
+
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_FORMAT,
+ (int)xid->formatID,
+ MLOG_4BYTES, mtr);
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_GTRID_LEN,
+ (int)xid->gtrid_length,
+ MLOG_4BYTES, mtr);
+ mlog_write_ulint(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_BQUAL_LEN,
+ (int)xid->bqual_length,
+ MLOG_4BYTES, mtr);
+ mlog_write_string(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_DATA,
+ (const unsigned char*) xid->data,
+ XIDDATASIZE, mtr);
}
void
-trx_sys_read_wsrep_checkpoint(XID* xid)
-/*===================================*/
+trx_sys_read_wsrep_checkpoint(
+/*==========================*/
+ XID* xid)
{
- trx_sysf_t* sys_header;
- mtr_t mtr;
- ulint magic;
+ trx_sysf_t* sys_header;
+ mtr_t mtr;
+ ulint magic;
- ut_ad(xid);
+ ut_ad(xid);
mtr_start(&mtr);
sys_header = trx_sysf_get(&mtr);
- if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
- + TRX_SYS_WSREP_XID_MAGIC_N_FLD))
- != TRX_SYS_WSREP_XID_MAGIC_N) {
- memset(xid, 0, sizeof(*xid));
- long long seqno= -1;
- memcpy(xid->data + 24, &seqno, sizeof(long long));
- xid->formatID = -1;
- trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
- mtr_commit(&mtr);
- return;
- }
-
- xid->formatID = (int)mach_read_from_4(
- sys_header
- + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT);
- xid->gtrid_length = (int)mach_read_from_4(
- sys_header
- + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN);
- xid->bqual_length = (int)mach_read_from_4(
- sys_header
- + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN);
- ut_memcpy(xid->data,
- sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA,
- XIDDATASIZE);
+ if ((magic = mach_read_from_4(sys_header + TRX_SYS_WSREP_XID_INFO
+ + TRX_SYS_WSREP_XID_MAGIC_N_FLD))
+ != TRX_SYS_WSREP_XID_MAGIC_N) {
+ memset(xid, 0, sizeof(*xid));
+ long long seqno= -1;
+ memcpy(xid->data + 24, &seqno, sizeof(long long));
+ xid->formatID = -1;
+ trx_sys_update_wsrep_checkpoint(xid, sys_header, &mtr);
+ mtr_commit(&mtr);
+ return;
+ }
+
+ xid->formatID = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_FORMAT);
+ xid->gtrid_length = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_GTRID_LEN);
+ xid->bqual_length = (int)mach_read_from_4(
+ sys_header
+ + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_BQUAL_LEN);
+ ut_memcpy(xid->data,
+ sys_header + TRX_SYS_WSREP_XID_INFO + TRX_SYS_WSREP_XID_DATA,
+ XIDDATASIZE);
mtr_commit(&mtr);
}
@@ -595,7 +591,6 @@ purge_pq_t*
trx_sys_init_at_db_start(void)
/*==========================*/
{
- mtr_t mtr;
purge_pq_t* purge_queue;
trx_sysf_t* sys_header;
ib_uint64_t rows_to_undo = 0;
@@ -607,12 +602,8 @@ trx_sys_init_at_db_start(void)
purge_queue = UT_NEW_NOKEY(purge_pq_t());
ut_a(purge_queue != NULL);
- mtr_start(&mtr);
-
- sys_header = trx_sysf_get(&mtr);
-
if (srv_force_recovery < SRV_FORCE_NO_UNDO_LOG_SCAN) {
- trx_rseg_array_init(sys_header, purge_queue, &mtr);
+ trx_rseg_array_init(purge_queue);
}
/* VERY important: after the database is started, max_trx_id value is
@@ -622,11 +613,17 @@ trx_sys_init_at_db_start(void)
to the disk-based header! Thus trx id values will not overlap when
the database is repeatedly started! */
+ mtr_t mtr;
+ mtr.start();
+
+ sys_header = trx_sysf_get(&mtr);
+
trx_sys->max_trx_id = 2 * TRX_SYS_TRX_ID_WRITE_MARGIN
+ ut_uint64_align_up(mach_read_from_8(sys_header
+ TRX_SYS_TRX_ID_STORE),
TRX_SYS_TRX_ID_WRITE_MARGIN);
+ mtr.commit();
ut_d(trx_sys->rw_max_trx_id = trx_sys->max_trx_id);
trx_dummy_sess = sess_open();
@@ -669,8 +666,6 @@ trx_sys_init_at_db_start(void)
trx_sys_mutex_exit();
- mtr_commit(&mtr);
-
return(purge_queue);
}
@@ -1101,17 +1096,15 @@ trx_sys_print_mysql_binlog_offset_from_page(
+ TRX_SYS_MYSQL_LOG_MAGIC_N_FLD)
== TRX_SYS_MYSQL_LOG_MAGIC_N) {
- fprintf(stderr,
- "mysqlbackup: Last MySQL binlog file position %lu %lu,"
- " file name %s\n",
- (ulong) mach_read_from_4(
+ ib::info() << "mysqlbackup: Last MySQL binlog file position "
+ << mach_read_from_4(
sys_header + TRX_SYS_MYSQL_LOG_INFO
- + TRX_SYS_MYSQL_LOG_OFFSET_HIGH),
- (ulong) mach_read_from_4(
+ + TRX_SYS_MYSQL_LOG_OFFSET_HIGH) << " "
+ << mach_read_from_4(
sys_header + TRX_SYS_MYSQL_LOG_INFO
- + TRX_SYS_MYSQL_LOG_OFFSET_LOW),
- sys_header + TRX_SYS_MYSQL_LOG_INFO
- + TRX_SYS_MYSQL_LOG_NAME);
+ + TRX_SYS_MYSQL_LOG_OFFSET_LOW)
+ << ", file name " << sys_header
+ + TRX_SYS_MYSQL_LOG_INFO + TRX_SYS_MYSQL_LOG_NAME;
}
}
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 6a524a5e586..4bdd3b2bec5 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -32,8 +32,12 @@ Created 3/26/1996 Heikki Tuuri
#include "trx0trx.ic"
#endif
+#ifdef WITH_WSREP
#include <mysql/service_wsrep.h>
+#endif
+
#include <mysql/service_thd_error_context.h>
+
#include "btr0sea.h"
#include "lock0lock.h"
#include "log0log.h"
@@ -59,11 +63,11 @@ Created 3/26/1996 Heikki Tuuri
#include <set>
#include <new>
-static const ulint MAX_DETAILED_ERROR_LEN = 256;
-
extern "C"
int thd_deadlock_victim_preference(const MYSQL_THD thd1, const MYSQL_THD thd2);
+static const ulint MAX_DETAILED_ERROR_LEN = 256;
+
/** Set of table_id */
typedef std::set<
table_id_t,
@@ -138,6 +142,7 @@ trx_init(
trx->op_info = "";
trx->active_commit_ordered = 0;
+
trx->isolation_level = TRX_ISO_REPEATABLE_READ;
trx->check_foreigns = true;
@@ -192,14 +197,20 @@ trx_init(
trx->lock.table_cached = 0;
- os_thread_id_t thread_id = trx->killed_by;
+ /* During asynchronous rollback, we should reset forced rollback flag
+ only after rollback is complete to avoid race with the thread owning
+ the transaction. */
- os_compare_and_swap_thread_id(&trx->killed_by, thread_id, 0);
+ if (!TrxInInnoDB::is_async_rollback(trx)) {
- /* Note: Do not set to 0, the ref count is decremented inside
- the TrxInInnoDB() destructor. We only need to clear the flags. */
+ os_thread_id_t thread_id = trx->killed_by;
+ os_compare_and_swap_thread_id(&trx->killed_by, thread_id, 0);
- trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK;
+ /* Note: Do not set to 0, the ref count is decremented inside
+ the TrxInInnoDB() destructor. We only need to clear the flags. */
+
+ trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK;
+ }
/* Note: It's possible that this list is not empty if a transaction
was interrupted after it collected the victim transactions and before
@@ -480,6 +491,7 @@ trx_create_low()
#ifdef WITH_WSREP
trx->wsrep_event = NULL;
#endif /* WITH_WSREP */
+
return(trx);
}
@@ -755,16 +767,7 @@ trx_resurrect_table_locks(
page_t* undo_rec_page = page_align(undo_rec);
if (undo_rec_page != undo_page) {
- if (!mtr_memo_release(&mtr,
- buf_block_align(undo_page),
- MTR_MEMO_PAGE_X_FIX)) {
- /* The page of the previous undo_rec
- should have been latched by
- trx_undo_page_get() or
- trx_undo_get_prev_rec(). */
- ut_ad(0);
- }
-
+ mtr.release_page(undo_page, MTR_MEMO_PAGE_X_FIX);
undo_page = undo_rec_page;
}
@@ -1376,8 +1379,8 @@ trx_start_low(
#endif /* UNIV_DEBUG */
#ifdef WITH_WSREP
- memset(trx->xid, 0, sizeof(xid_t));
- trx->xid->formatID = -1;
+ memset(trx->xid, 0, sizeof(xid_t));
+ trx->xid->formatID = -1;
#endif /* WITH_WSREP */
/* The initial value for trx->no: TRX_ID_MAX is used in
@@ -1570,16 +1573,14 @@ trx_serialisation_number_get(
Assign the transaction its history serialisation number and write the
update UNDO log record to the assigned rollback segment.
@return true if a serialisation log was written */
-static MY_ATTRIBUTE((nonnull))
bool
trx_write_serialisation_history(
/*============================*/
trx_t* trx, /*!< in/out: transaction */
mtr_t* mtr) /*!< in/out: mini-transaction */
{
-#ifdef WITH_WSREP
- trx_sysf_t* sys_header;
-#endif /* WITH_WSREP */
+ trx_sysf_t* sys_header = NULL;
+
/* Change the undo log segment states from TRX_UNDO_ACTIVE to some
other state: these modifications to the file data structure define
the transaction as committed in the file based domain, at the
@@ -1718,9 +1719,7 @@ trx_write_serialisation_history(
trx->mysql_log_file_name,
trx->mysql_log_offset,
TRX_SYS_MYSQL_LOG_INFO,
-#ifdef WITH_WSREP
- sys_header,
-#endif /* WITH_WSREP */
+ sys_header,
mtr);
trx->mysql_log_file_name = NULL;
@@ -1731,7 +1730,7 @@ trx_write_serialisation_history(
/********************************************************************
Finalize a transaction containing updates for a FTS table. */
-static MY_ATTRIBUTE((nonnull))
+static
void
trx_finalize_for_fts_table(
/*=======================*/
@@ -1764,7 +1763,7 @@ trx_finalize_for_fts_table(
/******************************************************************//**
Finalize a transaction containing updates to FTS tables. */
-static MY_ATTRIBUTE((nonnull))
+static
void
trx_finalize_for_fts(
/*=================*/
@@ -1816,7 +1815,7 @@ trx_flush_log_if_needed_low(
#endif /* _WIN32 */
switch (srv_flush_log_at_trx_commit) {
- case 3:
+ case 3:
case 2:
/* Write the log but do not flush it to disk */
flush = false;
@@ -1836,7 +1835,7 @@ trx_flush_log_if_needed_low(
/**********************************************************************//**
If required, flushes the log to disk based on the value of
innodb_flush_log_at_trx_commit. */
-static MY_ATTRIBUTE((nonnull))
+static
void
trx_flush_log_if_needed(
/*====================*/
@@ -1934,7 +1933,7 @@ trx_erase_lists(
/****************************************************************//**
Commits a transaction in memory. */
-static MY_ATTRIBUTE((nonnull))
+static
void
trx_commit_in_memory(
/*=================*/
@@ -2093,14 +2092,15 @@ trx_commit_in_memory(
trx_finalize_for_fts(trx, trx->undo_no != 0);
}
+ trx_mutex_enter(trx);
+ trx->dict_operation = TRX_DICT_OP_NONE;
+
#ifdef WITH_WSREP
if (wsrep_on(trx->mysql_thd)) {
trx->lock.was_chosen_as_deadlock_victim = FALSE;
}
#endif
- trx->dict_operation = TRX_DICT_OP_NONE;
-
/* Because we can rollback transactions asynchronously, we change
the state at the last step. trx_t::abort cannot change once commit
or rollback has started because we will have released the locks by
@@ -2108,14 +2108,8 @@ trx_commit_in_memory(
if (trx->abort) {
- trx_mutex_enter(trx);
-
trx->abort = false;
-
trx->state = TRX_STATE_FORCED_ROLLBACK;
-
- trx_mutex_exit(trx);
-
} else {
trx->state = TRX_STATE_NOT_STARTED;
}
@@ -2127,6 +2121,8 @@ trx_commit_in_memory(
trx_init(trx);
+ trx_mutex_exit(trx);
+
ut_a(trx->error_state == DB_SUCCESS);
}
@@ -2327,6 +2323,7 @@ trx_commit_or_rollback_prepare(
switch (trx->state) {
case TRX_STATE_NOT_STARTED:
case TRX_STATE_FORCED_ROLLBACK:
+
trx_start_low(trx, true);
/* fall through */
@@ -2446,17 +2443,6 @@ trx_commit_for_mysql(
case TRX_STATE_NOT_STARTED:
case TRX_STATE_FORCED_ROLLBACK:
- /* Update the info whether we should skip XA steps that eat
- CPU time.
-
- For the duration of the transaction trx->support_xa is
- not reread from thd so any changes in the value take
- effect in the next transaction. This is to avoid a
- scenario where some undo log records generated by a
- transaction contain XA information and other undo log
- records generated by the same transaction do not. */
- trx->support_xa = thd_supports_xa(trx->mysql_thd);
-
ut_d(trx->start_file = __FILE__);
ut_d(trx->start_line = __LINE__);
@@ -2775,16 +2761,8 @@ trx_weight_ge(
&& thd_has_edited_nontrans_tables(b->mysql_thd);
if (a_notrans_edit != b_notrans_edit) {
- return(a_notrans_edit);
- }
- /* First ask the upper server layer if it has any preference for which
- to prefer as a deadlock victim. */
- int pref= thd_deadlock_victim_preference(a->mysql_thd, b->mysql_thd);
- if (pref < 0) {
- return FALSE;
- } else if (pref > 0) {
- return TRUE;
+ return(a_notrans_edit);
}
/* Either both had edited non-transactional tables or both had
@@ -3022,11 +3000,11 @@ which is in the prepared state
@return trx on match, the trx->xid will be invalidated;
note that the trx may have been committed, unless the caller is
holding lock_sys->mutex */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
trx_t*
trx_get_trx_by_xid_low(
/*===================*/
- const XID* xid) /*!< in: X/Open XA transaction
+ XID* xid) /*!< in: X/Open XA transaction
identifier */
{
trx_t* trx;
@@ -3046,7 +3024,7 @@ trx_get_trx_by_xid_low(
if (trx->is_recovered
&& trx_state_eq(trx, TRX_STATE_PREPARED)
- && ((xid_t*)xid)->eq((xid_t*)trx->xid)) {
+ && xid->eq((XID*)trx->xid)) {
/* Invalidate the XID, so that subsequent calls
will not find it. */
@@ -3067,7 +3045,7 @@ holding lock_sys->mutex */
trx_t*
trx_get_trx_by_xid(
/*===============*/
- const XID* xid) /*!< in: X/Open XA transaction identifier */
+ XID* xid) /*!< in: X/Open XA transaction identifier */
{
trx_t* trx;
@@ -3080,7 +3058,7 @@ trx_get_trx_by_xid(
/* Recovered/Resurrected transactions are always only on the
trx_sys_t::rw_trx_list. */
- trx = trx_get_trx_by_xid_low(xid);
+ trx = trx_get_trx_by_xid_low((XID*)xid);
trx_sys_mutex_exit();
@@ -3098,18 +3076,6 @@ trx_start_if_not_started_xa_low(
switch (trx->state) {
case TRX_STATE_NOT_STARTED:
case TRX_STATE_FORCED_ROLLBACK:
-
- /* Update the info whether we should skip XA steps
- that eat CPU time.
-
- For the duration of the transaction trx->support_xa is
- not reread from thd so any changes in the value take
- effect in the next transaction. This is to avoid a
- scenario where some undo generated by a transaction,
- has XA stuff, and other undo, generated by the same
- transaction, doesn't. */
- trx->support_xa = thd_supports_xa(trx->mysql_thd);
-
trx_start_low(trx, read_write);
return;
@@ -3145,6 +3111,7 @@ trx_start_if_not_started_low(
switch (trx->state) {
case TRX_STATE_NOT_STARTED:
case TRX_STATE_FORCED_ROLLBACK:
+
trx_start_low(trx, read_write);
return;
@@ -3347,20 +3314,8 @@ trx_kill_blocking(trx_t* trx)
trx_t* victim_trx = it->m_trx;
ulint version = it->m_version;
+ /* Shouldn't commit suicide. */
ut_ad(victim_trx != trx);
-
- /* We don't kill transactions that are tagged
- explicitly as READ ONLY. */
-
- ut_a(!victim_trx->read_only);
-
-
- /* We should never kill background transactions. */
-
- ut_ad(victim_trx->mysql_thd != NULL);
-
- /* Shouldn't commit suicide either. */
-
ut_ad(victim_trx->mysql_thd != trx->mysql_thd);
/* Check that the transaction isn't active inside
@@ -3369,55 +3324,84 @@ trx_kill_blocking(trx_t* trx)
long time */
trx_mutex_enter(victim_trx);
+ ut_ad(version <= victim_trx->version);
- ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE));
+ ulint loop_count = 0;
+ /* start with optimistic sleep time of 20 micro seconds. */
+ ulint sleep_time = 20;
- while (victim_trx->version == version
- && (victim_trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) > 0
- && trx_is_started(victim_trx)) {
+ while ((victim_trx->in_innodb & TRX_FORCE_ROLLBACK_MASK) > 0
+ && victim_trx->version == version) {
trx_mutex_exit(victim_trx);
- os_thread_sleep(20);
+ loop_count++;
+ /* If the wait is long, don't hog the cpu. */
+ if (loop_count < 100) {
+ /* 20 microseconds */
+ sleep_time = 20;
+ } else if (loop_count < 1000) {
+ /* 1 millisecond */
+ sleep_time = 1000;
+ } else {
+ /* 100 milliseconds */
+ sleep_time = 100000;
+ }
+
+ os_thread_sleep(sleep_time);
trx_mutex_enter(victim_trx);
}
- ut_ad(it->m_version <= victim_trx->version);
-
- bool rollback = victim_trx->version == it->m_version;
-
- ut_ad(((victim_trx->in_innodb & TRX_FORCE_ROLLBACK)
- && victim_trx->killed_by == os_thread_get_curr_id())
- || !rollback);
-
- trx_mutex_exit(victim_trx);
+ /* Compare the version to check if the transaction has
+ already finished */
+ if (victim_trx->version != version) {
+ trx_mutex_exit(victim_trx);
+ continue;
+ }
- char buffer[1024];
+ /* We should never kill background transactions. */
+ ut_ad(victim_trx->mysql_thd != NULL);
- if (trx_is_started(victim_trx) && rollback) {
+ ut_ad(!(trx->in_innodb & TRX_FORCE_ROLLBACK_DISABLE));
+ ut_ad(victim_trx->in_innodb & TRX_FORCE_ROLLBACK);
+ ut_ad(victim_trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC);
+ ut_ad(victim_trx->killed_by == os_thread_get_curr_id());
+ ut_ad(victim_trx->version == it->m_version);
- trx_id_t id = victim_trx->id;
- /* JAN: TODO: MySQL 5.7
- char* thr_text = thd_security_context(
- victim_trx->mysql_thd,
- buffer, sizeof(buffer),
- 512);
- */
- thd_get_error_context_description(victim_trx->mysql_thd, buffer, sizeof(buffer),
- 512);
+ /* We don't kill Read Only, Background or high priority
+ transactions. */
+ ut_a(!victim_trx->read_only);
+ ut_a(victim_trx->mysql_thd != NULL);
- ut_ad(victim_trx->in_innodb & TRX_FORCE_ROLLBACK_ASYNC);
+ trx_mutex_exit(victim_trx);
- ut_ad(victim_trx->version == it->m_version);
+#ifdef UNIV_DEBUG
+ char buffer[1024];
+ char* thr_text;
+ trx_id_t id;
+
+ thr_text = thd_get_error_context_description(victim_trx->mysql_thd,
+ buffer, sizeof(buffer),
+ 512);
+ id = victim_trx->id;
+#endif /* UNIV_DEBUG */
+ trx_rollback_for_mysql(victim_trx);
- trx_rollback_for_mysql(victim_trx);
+#ifdef UNIV_DEBUG
+ ib::info() << "High Priority Transaction (ID): "
+ << trx->id << " killed transaction (ID): "
+ << id << " in hit list"
+ << " - " << thr_text;
+#endif /* UNIV_DEBUG */
+ trx_mutex_enter(victim_trx);
- ib::info() << "Killed transaction: ID: " << id
- << " - "; // << thr_text;
- }
+ version++;
+ ut_ad(victim_trx->version == version);
- trx_mutex_enter(victim_trx);
+ os_thread_id_t thread_id = victim_trx->killed_by;
+ os_compare_and_swap_thread_id(&victim_trx->killed_by,
+ thread_id, 0);
victim_trx->in_innodb &= TRX_FORCE_ROLLBACK_MASK;
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index 28ec3b58dd3..bd2cc5ab040 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -436,7 +436,7 @@ trx_undo_page_init(
Creates a new undo log segment in file.
@return DB_SUCCESS if page creation OK possible error codes are:
DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE */
-static MY_ATTRIBUTE((nonnull, warn_unused_result))
+static MY_ATTRIBUTE((warn_unused_result))
dberr_t
trx_undo_seg_create(
/*================*/
@@ -1087,7 +1087,7 @@ trx_undo_empty_header_page(
Truncates an undo log from the end. This function is used during a rollback
to free space from an undo log. */
void
-trx_undo_truncate_end(
+trx_undo_truncate_end_func(
/*=======================*/
trx_t* trx, /*!< in: transaction whose undo log it is */
trx_undo_t* undo, /*!< in: undo log */
@@ -1615,10 +1615,7 @@ trx_undo_create(
offset = trx_undo_header_create(undo_page, trx_id, mtr);
- if (trx->support_xa) {
- trx_undo_header_add_space_for_xid(undo_page,
- undo_page + offset, mtr);
- }
+ trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr);
*undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
page_no, offset);
@@ -1689,10 +1686,8 @@ trx_undo_reuse_cached(
if (type == TRX_UNDO_INSERT) {
offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
- if (trx->support_xa) {
- trx_undo_header_add_space_for_xid(
- undo_page, undo_page + offset, mtr);
- }
+ trx_undo_header_add_space_for_xid(
+ undo_page, undo_page + offset, mtr);
} else {
ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
+ TRX_UNDO_PAGE_TYPE)
@@ -1700,10 +1695,8 @@ trx_undo_reuse_cached(
offset = trx_undo_header_create(undo_page, trx_id, mtr);
- if (trx->support_xa) {
- trx_undo_header_add_space_for_xid(
- undo_page, undo_page + offset, mtr);
- }
+ trx_undo_header_add_space_for_xid(
+ undo_page, undo_page + offset, mtr);
}
trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
diff --git a/storage/innobase/ut/ut0crc32.cc b/storage/innobase/ut/ut0crc32.cc
index 1e4cc7b8de4..1ec8ddd1581 100644
--- a/storage/innobase/ut/ut0crc32.cc
+++ b/storage/innobase/ut/ut0crc32.cc
@@ -117,7 +117,7 @@ ut_crc32_swap_byteorder(
/* CRC32 hardware implementation. */
/* Flag that tells whether the CPU supports CRC32 or not */
-UNIV_INTERN bool ut_crc32_sse2_enabled = false;
+bool ut_crc32_sse2_enabled = false;
UNIV_INTERN bool ut_crc32_power8_enabled = false;
#if defined(__GNUC__) && defined(__x86_64__)
diff --git a/storage/innobase/ut/ut0dbg.cc b/storage/innobase/ut/ut0dbg.cc
index 673c8d9150d..bcf9d5fd1b5 100644
--- a/storage/innobase/ut/ut0dbg.cc
+++ b/storage/innobase/ut/ut0dbg.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -42,8 +42,8 @@ ut_dbg_assertion_failed(
file, line);
#else /* UNIV_HOTBACKUP */
fprintf(stderr,
- " InnoDB: Assertion failure in thread %lu"
- " in file %s line %lu\n",
+ " InnoDB: Assertion failure in thread " ULINTPF
+ " in file %s line " ULINTPF "\n",
os_thread_pf(os_thread_get_curr_id()),
innobase_basename(file), line);
#endif /* UNIV_HOTBACKUP */
diff --git a/storage/innobase/ut/ut0new.cc b/storage/innobase/ut/ut0new.cc
index ed725819b8a..c2e3eb813af 100644
--- a/storage/innobase/ut/ut0new.cc
+++ b/storage/innobase/ut/ut0new.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 2014, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2014, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -179,7 +179,7 @@ ut_new_boot()
for (size_t i = 0; i < n_auto; i++) {
const std::pair<mem_keys_auto_t::iterator, bool> ret
- __attribute__((unused))
+ MY_ATTRIBUTE((unused))
= mem_keys_auto.insert(
mem_keys_auto_t::value_type(auto_event_names[i],
&auto_event_keys[i]));
diff --git a/storage/innobase/ut/ut0rnd.cc b/storage/innobase/ut/ut0rnd.cc
index 2ff6248b0b4..2d2d8977ad7 100644
--- a/storage/innobase/ut/ut0rnd.cc
+++ b/storage/innobase/ut/ut0rnd.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2014, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
diff --git a/storage/innobase/ut/ut0ut.cc b/storage/innobase/ut/ut0ut.cc
index ac71c3280a6..81e3fb1ab90 100644
--- a/storage/innobase/ut/ut0ut.cc
+++ b/storage/innobase/ut/ut0ut.cc
@@ -1,6 +1,6 @@
/*****************************************************************************
-Copyright (c) 1994, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 1994, 2016, Oracle and/or its affiliates. All Rights Reserved.
This program is free software; you can redistribute it and/or modify it under
the terms of the GNU General Public License as published by the Free Software
@@ -227,14 +227,14 @@ ut_print_timestamp(
GetLocalTime(&cal_tm);
- fprintf(file, "%d-%02d-%02d %02d:%02d:%02d %#lx",
+ fprintf(file, "%d-%02d-%02d %02d:%02d:%02d %#llx",
(int) cal_tm.wYear,
(int) cal_tm.wMonth,
(int) cal_tm.wDay,
(int) cal_tm.wHour,
(int) cal_tm.wMinute,
(int) cal_tm.wSecond,
- thread_id);
+ static_cast<ulonglong>(thread_id));
#else
struct tm* cal_tm_ptr;
time_t tm;
@@ -369,17 +369,19 @@ ut_get_year_month_day(
Runs an idle loop on CPU. The argument gives the desired delay
in microseconds on 100 MHz Pentium + Visual C++.
@return dummy value */
-void
+ulint
ut_delay(
/*=====*/
ulint delay) /*!< in: delay in microseconds on 100 MHz Pentium */
{
- ulint i;
+ ulint i, j;
UT_LOW_PRIORITY_CPU();
+ j = 0;
for (i = 0; i < delay * 50; i++) {
+ j += i;
UT_RELAX_CPU();
UT_COMPILER_BARRIER();
}
@@ -387,6 +389,7 @@ ut_delay(
UT_RESUME_PRIORITY_CPU();
UT_RESUME_PRIORITY_CPU();
+ return(j);
}
#endif /* UNIV_HOTBACKUP */
@@ -404,10 +407,10 @@ ut_print_buf(
UNIV_MEM_ASSERT_RW(buf, len);
- fprintf(file, " len %lu; hex ", len);
+ fprintf(file, " len " ULINTPF "; hex ", len);
for (data = (const byte*) buf, i = 0; i < len; i++) {
- fprintf(file, "%02lx", (ulong)*data++);
+ fprintf(file, "%02lx", static_cast<ulong>(*data++));
}
fputs("; asc ", file);
@@ -673,12 +676,10 @@ ut_snprintf(
}
#endif /* _WIN32 */
-/**********************************************************************//**
-Outputs a fixed-length string, quoted as an SQL identifier.
-If the string contains a slash '/', the string will be
-output as two identifiers separated by a period (.),
-as in SQL database_name.identifier. */
-UNIV_INTERN
+/** Convert an error number to a human readable text message.
+The returned string is static and should not be freed or modified.
+@param[in] num InnoDB internal error number
+@return string, describing the error */
std::string
ut_get_name(
/*=========*/
@@ -844,6 +845,10 @@ ut_strerr(
return("Punch hole not supported by the file system");
case DB_IO_NO_PUNCH_HOLE_TABLESPACE:
return("Punch hole not supported by the tablespace");
+ case DB_IO_NO_ENCRYPT_TABLESPACE:
+ return("Page encryption not supported by the tablespace");
+ case DB_IO_DECRYPT_FAIL:
+ return("Page decryption failed after reading from disk");
case DB_IO_PARTIAL_FAILED:
return("Partial IO failed");
case DB_FORCED_ABORT:
@@ -854,6 +859,9 @@ ut_strerr(
case DB_COMPUTE_VALUE_FAILED:
return("Compute generated column failed");
+ case DB_NO_FK_ON_S_BASE_COL:
+ return("Cannot add foreign key on the base column "
+ "of stored column");
/* do not add default: in order to produce a warning if new code
is added to the enum but not added here */
diff --git a/storage/innobase/ut/ut0wqueue.cc b/storage/innobase/ut/ut0wqueue.cc
index 3df32d92a9b..cee30925375 100644
--- a/storage/innobase/ut/ut0wqueue.cc
+++ b/storage/innobase/ut/ut0wqueue.cc
@@ -198,7 +198,6 @@ ib_wqueue_nowait(
return (node ? node->data : NULL);
}
-
/********************************************************************
Check if queue is empty. */
ibool