[Commits] fec844a: Merge InnoDB 5.7 from mysql-5.7.14.
Jan Lindström
jan.lindstrom at mariadb.com
Thu Sep 8 15:49:44 EEST 2016
revision-id: fec844aca88e1c6b9c36bb0b811e92d9d023ffb9 (mariadb-10.2.1-5-gfec844a)
parent(s): 2e814d4702d71a04388386a9f591d14a35980bfe
committer: Jan Lindström
timestamp: 2016-09-08 15:49:03 +0300
message:
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
---
include/my_base.h | 13 +-
include/my_handler_errors.h | 13 +-
mysql-test/disabled.def | 4 -
mysql-test/include/have_no_undo_tablespaces.inc | 4 +
mysql-test/include/mix1.inc | 9 +-
mysql-test/r/partition_innodb_plugin.result | 1 +
mysql-test/suite/galera/r/create.result | 4 +
mysql-test/suite/handler/disabled.def | 2 -
mysql-test/suite/handler/innodb.result | 1 +
mysql-test/suite/innodb/disabled.def | 2 +-
.../suite/innodb/include/show_i_s_tablespaces.inc | 38 +
.../suite/innodb/r/innodb-wl5522-debug-zip.result | 1 +
.../innodb/r/innodb_information_schema.result | 8 +-
mysql-test/suite/innodb/r/innodb_mysql.result | 4 +
.../suite/innodb/t/innodb-wl5522-debug-zip.test | 1 +
mysql-test/suite/innodb/t/innodb.test | 2 +-
mysql-test/suite/innodb/t/innodb_mysql-master.opt | 4 +-
.../innodb/t/innodb_simulate_comp_failures.test | 1 +
mysql-test/suite/innodb_zip/r/16k.result | 150 +-
.../innodb_zip/r/wl6347_comp_indx_stat.result | 6 -
mysql-test/suite/innodb_zip/r/wl6560.result | 418 ---
mysql-test/suite/innodb_zip/r/wl6915_1.result | 39 +-
mysql-test/suite/innodb_zip/t/16k-master.opt | 3 +
mysql-test/suite/innodb_zip/t/16k.test | 8 +-
mysql-test/suite/innodb_zip/t/disabled.def | 2 +-
mysql-test/suite/innodb_zip/t/large_blob.test | 2 +-
mysql-test/suite/innodb_zip/t/wl6560.test | 7 +-
mysql-test/suite/innodb_zip/t/wl6915_1.test | 4 +-
.../sys_vars/r/innodb_support_xa_basic.result | 78 +-
.../suite/sys_vars/r/innodb_support_xa_func.result | 16 +-
mysql-test/t/partition_innodb_plugin.test | 2 +
mysql-test/t/row-checksum.opt | 1 +
sql/handler.cc | 16 +-
sql/share/errmsg-utf8.txt | 18 +
storage/innobase/CMakeLists.txt | 405 +--
storage/innobase/api/api0api.cc | 24 +-
storage/innobase/api/api0misc.cc | 64 +-
storage/innobase/btr/btr0btr.cc | 186 +-
storage/innobase/btr/btr0bulk.cc | 37 +-
storage/innobase/btr/btr0cur.cc | 224 +-
storage/innobase/btr/btr0defragment.cc | 30 +-
storage/innobase/btr/btr0scrub.cc | 5 +-
storage/innobase/btr/btr0sea.cc | 26 +-
storage/innobase/buf/buf0buf.cc | 386 ++-
storage/innobase/buf/buf0checksum.cc | 6 +-
storage/innobase/buf/buf0dblwr.cc | 13 +-
storage/innobase/buf/buf0dump.cc | 44 +-
storage/innobase/buf/buf0flu.cc | 176 +-
storage/innobase/buf/buf0lru.cc | 57 +-
storage/innobase/buf/buf0mtflu.cc | 2 +-
storage/innobase/buf/buf0rea.cc | 13 +-
storage/innobase/data/data0data.cc | 3 +-
storage/innobase/dict/dict0boot.cc | 2 +-
storage/innobase/dict/dict0crea.cc | 203 +-
storage/innobase/dict/dict0defrag_bg.cc | 403 +++
storage/innobase/dict/dict0dict.cc | 318 +-
storage/innobase/dict/dict0load.cc | 280 +-
storage/innobase/dict/dict0mem.cc | 285 +-
storage/innobase/dict/dict0stats.cc | 149 +-
storage/innobase/dict/dict0stats_bg.cc | 274 +-
storage/innobase/fil/fil0crypt.cc | 2 +-
storage/innobase/fil/fil0fil.cc | 1088 ++++---
storage/innobase/fsp/fsp0file.cc | 132 +-
storage/innobase/fsp/fsp0fsp.cc | 607 +++-
storage/innobase/fsp/fsp0space.cc | 30 +-
storage/innobase/fsp/fsp0sysspace.cc | 27 +-
storage/innobase/fts/fts0ast.cc | 34 +-
storage/innobase/fts/fts0fts.cc | 103 +-
storage/innobase/fts/fts0opt.cc | 54 +-
storage/innobase/fts/fts0que.cc | 63 +-
storage/innobase/gis/gis0rtree.cc | 139 +-
storage/innobase/gis/gis0sea.cc | 123 +-
storage/innobase/handler/ha_innodb.cc | 3030 ++++++++++++--------
storage/innobase/handler/ha_innodb.h | 664 +++--
storage/innobase/handler/ha_innopart.cc | 245 +-
storage/innobase/handler/ha_innopart.h | 22 +-
storage/innobase/handler/handler0alter.cc | 1579 +++++++---
storage/innobase/handler/i_s.cc | 461 +--
storage/innobase/ibuf/ibuf0ibuf.cc | 69 +-
storage/innobase/include/api0api.h | 9 +-
storage/innobase/include/btr0btr.h | 47 +-
storage/innobase/include/btr0bulk.h | 2 +-
storage/innobase/include/btr0sea.h | 7 +
storage/innobase/include/btr0sea.ic | 6 +-
storage/innobase/include/btr0types.h | 2 +-
storage/innobase/include/buf0buf.h | 65 +-
storage/innobase/include/buf0buf.ic | 71 +-
storage/innobase/include/buf0checksum.h | 7 +-
storage/innobase/include/buf0dblwr.h | 4 +-
storage/innobase/include/buf0flu.h | 29 +-
storage/innobase/include/buf0rea.h | 7 -
storage/innobase/include/data0data.h | 38 +-
storage/innobase/include/data0data.ic | 31 +-
storage/innobase/include/db0err.h | 13 +-
storage/innobase/include/dict0crea.h | 14 +
storage/innobase/include/dict0defrag_bg.h | 93 +
storage/innobase/include/dict0dict.h | 137 +-
storage/innobase/include/dict0dict.ic | 101 +-
storage/innobase/include/dict0load.h | 10 +-
storage/innobase/include/dict0mem.h | 185 +-
storage/innobase/include/dict0stats.h | 36 +
storage/innobase/include/dict0stats_bg.h | 46 +-
storage/innobase/include/dict0types.h | 29 +-
storage/innobase/include/dyn0buf.h | 22 +-
storage/innobase/include/fil0crypt.ic | 2 +-
storage/innobase/include/fil0fil.h | 472 +--
storage/innobase/include/fsp0file.h | 42 +-
storage/innobase/include/fsp0fsp.h | 117 +-
storage/innobase/include/fsp0fsp.ic | 27 +-
storage/innobase/include/fsp0space.h | 21 +-
storage/innobase/include/fsp0sysspace.h | 24 +-
storage/innobase/include/fsp0types.h | 30 +-
storage/innobase/include/fts0ast.h | 7 +
storage/innobase/include/fts0fts.h | 95 +-
storage/innobase/include/fts0priv.h | 56 +-
storage/innobase/include/fts0priv.ic | 17 +-
storage/innobase/include/fut0fut.h | 4 +-
storage/innobase/include/gis0rtree.h | 21 +-
storage/innobase/include/ha0ha.h | 2 +-
storage/innobase/include/ha_prototypes.h | 16 +-
storage/innobase/include/ibuf0ibuf.h | 8 +-
storage/innobase/include/lock0lock.h | 48 +-
storage/innobase/include/lock0prdt.h | 23 +-
storage/innobase/include/lock0priv.h | 75 +-
storage/innobase/include/log0log.h | 72 +-
storage/innobase/include/log0log.ic | 7 +-
storage/innobase/include/log0recv.h | 16 +-
storage/innobase/include/mach0data.h | 29 +-
storage/innobase/include/mach0data.ic | 2 +-
storage/innobase/include/mem0mem.h | 2 +-
storage/innobase/include/mem0mem.ic | 2 +-
storage/innobase/include/mtr0log.ic | 24 +-
storage/innobase/include/mtr0mtr.h | 44 +-
storage/innobase/include/mtr0mtr.ic | 2 +-
storage/innobase/include/os0atomic.h | 79 +-
storage/innobase/include/os0atomic.ic | 11 +-
storage/innobase/include/os0file.h | 358 ++-
storage/innobase/include/os0file.ic | 11 +-
storage/innobase/include/os0thread.h | 9 +-
storage/innobase/include/page0cur.h | 3 +-
storage/innobase/include/page0page.h | 24 +-
storage/innobase/include/page0types.h | 15 +-
storage/innobase/include/page0zip.h | 52 +-
storage/innobase/include/page0zip.ic | 3 +-
storage/innobase/include/pars0pars.h | 18 +-
storage/innobase/include/que0que.h | 16 +-
storage/innobase/include/read0read.h | 2 +-
storage/innobase/include/read0types.h | 4 +-
storage/innobase/include/rem0cmp.h | 21 +-
storage/innobase/include/rem0rec.h | 81 +-
storage/innobase/include/rem0rec.ic | 2 +-
storage/innobase/include/row0ftsort.h | 2 +-
storage/innobase/include/row0ins.h | 8 +-
storage/innobase/include/row0log.h | 17 +-
storage/innobase/include/row0merge.h | 86 +-
storage/innobase/include/row0mysql.h | 72 +-
storage/innobase/include/row0purge.h | 2 +-
storage/innobase/include/row0row.h | 10 +-
storage/innobase/include/row0sel.h | 9 +-
storage/innobase/include/row0umod.h | 2 +-
storage/innobase/include/row0undo.h | 4 +-
storage/innobase/include/row0upd.h | 62 +-
storage/innobase/include/row0vers.h | 9 +-
storage/innobase/include/srv0mon.h | 10 +-
storage/innobase/include/srv0srv.h | 34 +-
storage/innobase/include/srv0start.h | 11 +
storage/innobase/include/sync0arr.h | 6 +-
storage/innobase/include/sync0rw.h | 14 +-
storage/innobase/include/sync0sync.h | 5 +-
storage/innobase/include/sync0types.h | 7 +-
storage/innobase/include/trx0rec.h | 4 +
storage/innobase/include/trx0rseg.h | 7 +-
storage/innobase/include/trx0sys.h | 21 +-
storage/innobase/include/trx0sys.ic | 8 +-
storage/innobase/include/trx0trx.h | 62 +-
storage/innobase/include/trx0types.h | 2 +-
storage/innobase/include/trx0undo.h | 11 +-
storage/innobase/include/univ.i | 46 +-
storage/innobase/include/ut0counter.h | 8 +-
storage/innobase/include/ut0crc32.h | 2 +-
storage/innobase/include/ut0dbg.h | 2 +-
storage/innobase/include/ut0lst.h | 1 -
storage/innobase/include/ut0mem.h | 2 +-
storage/innobase/include/ut0new.h | 11 +-
storage/innobase/include/ut0rnd.h | 2 +-
storage/innobase/include/ut0rnd.ic | 2 +-
storage/innobase/include/ut0ut.h | 35 +-
storage/innobase/include/ut0wqueue.h | 1 -
storage/innobase/innodb.cmake | 272 +-
storage/innobase/lock/lock0lock.cc | 940 +++---
storage/innobase/lock/lock0prdt.cc | 33 +-
storage/innobase/lock/lock0wait.cc | 14 +-
storage/innobase/log/log0crypt.cc | 2 -
storage/innobase/log/log0log.cc | 336 ++-
storage/innobase/log/log0recv.cc | 847 +++++-
storage/innobase/mtr/mtr0log.cc | 14 +-
storage/innobase/mtr/mtr0mtr.cc | 193 +-
storage/innobase/os/os0file.cc | 1238 +++++++-
storage/innobase/os/os0sync.cc | 935 ------
storage/innobase/os/os0thread.cc | 15 +-
storage/innobase/page/page0zip.cc | 87 +-
storage/innobase/pars/lexyy.cc | 2 +-
storage/innobase/pars/pars0pars.cc | 21 +-
storage/innobase/que/que0que.cc | 19 +-
storage/innobase/rem/rem0cmp.cc | 58 +-
storage/innobase/rem/rem0rec.cc | 15 +-
storage/innobase/row/row0ftsort.cc | 30 +-
storage/innobase/row/row0import.cc | 303 +-
storage/innobase/row/row0ins.cc | 160 +-
storage/innobase/row/row0log.cc | 51 +-
storage/innobase/row/row0merge.cc | 252 +-
storage/innobase/row/row0mysql.cc | 239 +-
storage/innobase/row/row0purge.cc | 33 +
storage/innobase/row/row0quiesce.cc | 245 +-
storage/innobase/row/row0row.cc | 16 +-
storage/innobase/row/row0sel.cc | 82 +-
storage/innobase/row/row0trunc.cc | 64 +-
storage/innobase/row/row0uins.cc | 2 +-
storage/innobase/row/row0umod.cc | 30 -
storage/innobase/row/row0undo.cc | 2 +-
storage/innobase/row/row0upd.cc | 313 +-
storage/innobase/row/row0vers.cc | 242 +-
storage/innobase/srv/srv0conc.cc | 13 +
storage/innobase/srv/srv0mon.cc | 7 +-
storage/innobase/srv/srv0srv.cc | 166 +-
storage/innobase/srv/srv0start.cc | 136 +-
storage/innobase/sync/sync0arr.cc | 26 +-
storage/innobase/sync/sync0debug.cc | 17 +-
storage/innobase/sync/sync0rw.cc | 46 +-
storage/innobase/sync/sync0sync.cc | 10 +-
storage/innobase/trx/trx0i_s.cc | 1 -
storage/innobase/trx/trx0purge.cc | 13 +-
storage/innobase/trx/trx0rec.cc | 161 +-
storage/innobase/trx/trx0roll.cc | 18 +-
storage/innobase/trx/trx0rseg.cc | 30 +-
storage/innobase/trx/trx0sys.cc | 225 +-
storage/innobase/trx/trx0trx.cc | 226 +-
storage/innobase/trx/trx0undo.cc | 21 +-
storage/innobase/ut/ut0crc32.cc | 2 +-
storage/innobase/ut/ut0dbg.cc | 6 +-
storage/innobase/ut/ut0new.cc | 4 +-
storage/innobase/ut/ut0rnd.cc | 2 +-
storage/innobase/ut/ut0ut.cc | 34 +-
storage/innobase/ut/ut0wqueue.cc | 1 -
244 files changed, 15710 insertions(+), 9153 deletions(-)
diff --git a/include/my_base.h b/include/my_base.h
index 1317639..af05336 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 5af6a35..3d05fb7 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 75704c7..e82ddcf 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 0000000..4c163e7
--- /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 bfe1567..7eae423 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 35b1e31..16b5daa 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 b93cd7b..4d6488d 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 ef63577..888298b 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 1022376..f3c0f79 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 778ce48..86fb294 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 0000000..a79bc3c
--- /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 ae4e96d..57edf7a 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 33dc50d..15c3af3 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 900e381..a057719 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 c61d10e..762b475 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 79a00c2..d129e86 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 a177f285..a1ee2c0 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 cf22935..5a4978c 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 3d9f395..8604932 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 3b98527..509ffe9 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 bf46d8a..0000000
--- 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 0ffc2f4..bba8109 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 0000000..82f574a
--- /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 274b0b8..2885d13 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 d3799d0..2808bc5 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 dc1dc2e..b9888cc 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 041dd45..55d3674 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 625c8a3..7f0f734 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 754b093..8384ee3 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
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
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 7291b60..d86cf89 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 3a3ae25..a514736 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 0000000..977b569
--- /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 3fbd1b3..6e9d8dc 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 8dfa519..7c3c4ab 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 b835d6b..44b1cfa 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 1f04b1b..1b99dcf 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.
+ at param[in] crsr InnoDB Cursor
+ at 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 c83eaed..3864e4b 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 36ec01d..2557882 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.
- at return inserted record or NULL if run out of space */
+ at 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 @@ btr_page_split_and_insert(
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 @@ btr_page_split_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);
@@ -3164,7 +3154,6 @@ btr_page_split_and_insert(
@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 @@ btr_compress(
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 @@ btr_compress(
/* 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 @@ btr_compress(
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 @@ btr_compress(
/* 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 @@ btr_compress(
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 4a3de74..9ff3bc5 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 ab8ee1d..7daec06 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 @@ btr_cur_search_to_nth_level(
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 @@ btr_cur_search_to_nth_level(
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 @@ btr_cur_optimistic_insert(
#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 @@ btr_cur_optimistic_insert(
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 @@ btr_cur_optimistic_update(
#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 @@ btr_store_big_rec_extern_fields(
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 @@ btr_store_big_rec_extern_fields(
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 bacc3a4..e4202b9 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 at 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 88ec4f0..8ed0117 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 60104b6..4489775 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 @@ btr_search_drop_page_hash_index(buf_block_t* block)
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 04260df..bc4efa4 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.
- at param[in] read_buf database page
- at param[in] checksum_field1 new checksum field
- at param[in] checksum_field2 old checksum field
- at param[in] page_no page number of given read_buf
- at param[in] is_log_enabled true if log option is enabled
- at param[in] log_file file pointer to log_file
- at param[in] curr_algo current checksum algorithm
+ at param[in] read_buf database page
+ at param[in] checksum_field1 new checksum field
+ at param[in] checksum_field2 old checksum field
+ at param[in] page_no page number of given read_buf
+ at param[in] is_log_enabled true if log option is enabled
+ at param[in] log_file file pointer to log_file
+ at param[in] curr_algo current checksum algorithm
+ at 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 @@ buf_pool_resize()
}
}
- 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 @@ buf_page_get_zip(
/* 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.
+ at 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 @@ buf_page_io_complete(
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 @@ buf_page_io_complete(
/* 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 935c8a7..94eafec 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 64ecb54..ff1d205 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 @@ buf_dblwr_add_to_batch(
} 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 831dd13..ede7b02 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.
+ at 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 227c71c..8c7c9f6 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
- at param[out] n the number of pages which were processed is
+ at 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).
+ at param[in] thd thread handle
+ at param[in] var pointer to system variable
+ at param[out] var_ptr where the formal string goes
+ at 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 @@ DECLARE_THREAD(buf_flush_page_cleaner_coordinator)(
/* 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 1cb46ae..5d20777 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 @@ buf_LRU_free_page(
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 06aaac3..117de5c 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 5de0412..e96c61d 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 b4df869..4b788c8 100644
--- a/storage/innobase/data/data0data.cc
+++ b/storage/innobase/data/data0data.cc
@@ -447,7 +447,7 @@ dfield_print_also_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 4ffcf64..5c4e204 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 5c7d41a..3195242 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
+ at param[in] col_name column name for the column to be checked
+ at param[in] index the index to be searched
+ at 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
+ at param[in] fk_col_name FK column name to be checked
+ at param[in] table the table
+ at 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.
+ at param[in] col_name column name for the column to be checked
+ at param[in] table the table
+ at 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.
+ at param[in] col_name column name to be searched for fk constraint
+ at param[in] table table to which foreign key constraint belongs
+ at 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
+ at param[in] local_fk_set set of foreign key objects, to be added to
+the dictionary tables
+ at param[in] table table to which the foreign key objects in
+local_fk_set belong to
+ at 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
+ at param[in] table table
+ at param[in] fk_col_name name for the column to be checked
+ at 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 0000000..82aa3ab
--- /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
+
+*****************************************************************************/
+
+/**************************************************//**
+ at 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.
+ at 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.
+ at 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.
+ at 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 687353c..6a33de6 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 @@ dict_create_foreign_constraints_low(
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 @@ dict_create_foreign_constraints_low(
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 @@ dict_create_foreign_constraints_low(
}
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 @@ dict_create_foreign_constraints_low(
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 @@ dict_foreign_parse_drop_constraints(
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
+ at 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.
- at param[in] space Tablespace ID to search for.
+ at 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.
+ at param[in] name Tablespace name to search for.
+ at 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 5267cf1..f38ad85 100644
--- a/storage/innobase/dict/dict0load.cc
+++ b/storage/innobase/dict/dict0load.cc
@@ -733,7 +733,6 @@ dict_process_sys_datafiles(
@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 @@ dict_load_table_one(
}
}
+ /* 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 @@ dict_load_table_one(
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 @@ dict_load_table_on_id(
return(table);
}
-/***********************************************************************//**
-Loads a table id based on the index id.
- at 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 @@ dict_load_foreigns(
DBUG_RETURN(DB_SUCCESS);
}
+
+/***********************************************************************//**
+Loads a table id based on the index id.
+ at 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 89e9861..b0d679d 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
- at 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.
+ at param[in] table table
+ at 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.
+ at param[in] index virtual index
+ at 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.
+ at param[in] col_name column name
+ at param[in] table innodb table object
+ at 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
+ at param[in] col_name column name
+ at param[in] table table object
+ at 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
+ at 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.
+ at 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.
+ at 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
+ at 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 67bf672..3c25e37 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.
- at 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.
- at 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 eca3756..dbc8e90 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.
- at 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).
+ at param[in] thd thread handle
+ at param[in] var pointer to system variable
+ at param[out] var_ptr where the formal string goes
+ at 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 fb87262..9062bf1 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 a28be69..3d34de6 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.
+ at 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.
+ at 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.
- at 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.
+ at 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.
- at 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.
+ at param[in] space_id tablespace id
+ at param[in] old_path old filepath
+ at param[in] new_path new filepath
+ at param[in] is_discarded whether the tablespace is discarded
+ at 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 @@ fil_rename_tablespace(
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 @@ fil_rename_tablespace(
<< " 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 @@ fil_rename_tablespace(
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 @@ fil_rename_tablespace(
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 @@ fil_rename_tablespace(
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
- at param[in] size Initial size of the tablespace file in pages,
-must be >= FIL_IBD_FILE_INITIAL_SIZE
+ at param[in] size Initial size of the tablespace file in
+ pages, must be >= FIL_IBD_FILE_INITIAL_SIZE
+ at param[in] mode MariaDB encryption mode
+ at 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 @@ fil_ibd_open(
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
+ at 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 @@ fil_space_for_table_exists_in_mem(
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 @@ fil_space_extend(
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 @@ fil_space_extend(
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 @@ fil_space_extend(
ib::warn()
<< "Error while writing " << len
- << " zeroes to " << node->name
+ << " zeroes to " << name
<< " starting at offset " << node_start;
}
}
@@ -4991,6 +5109,10 @@ fil_space_extend(
} 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.
+ at param[in,out] req_type IO request
+ at param[in] page_id page id
+ at 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
-
+ at 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 @@ fil_flush(
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
- at return whether the operation succeeded */
-bool
+ at 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
- at param[in] space Space ID of tablespace for which to set
- at param[in] algorithm Text representation of the algorithm
+#ifdef MYSQL_COMPRESSION_ENCRYPTION
+
+/** Set the compression type for the tablespace of a table
+ at param[in] table The table that should be compressed
+ at 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
+ at param[in] space_id Space ID of tablespace for which to set
+ at param[in] algorithm Encryption algorithm
+ at param[in] key Encryption key
+ at param[in] iv Encryption iv
+ at 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.
+ at 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.
+ at 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 b3e85c5..501a8e5 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.
- at param[in] flags The expected tablespace flags.
+ at param[in] flags The expected tablespace flags.
+ at 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
+ at 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 109299a..9dc99f3 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.
+ at param[in] page_size page size.
+ at 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.
+ at param[in] space tablespace
+ at param[in,out] encrypt_info buffer for encrypt key.
+ at 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.
+ at param[in] space tablespace
+ at param[in] encrypt_info buffer for re-encrypt key.
+ at param[in,out] mtr mini-transaction
+ at 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.
+ at param[in/out] key key
+ at param[in/out] iv iv
+ at param[in] encryption_info encrytion info.
+ at 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.
+ at param[in] fsp_flags tablespace flags
+ at param[in/out] key tablespace key
+ at param[in/out] iv tablespace iv
+ at param[in] page first page of a tablespace
+ at 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
- at return true if there were at least 3 free pages, or we were able to extend */
+ at param[in] n_pages number of pages to reserve
+ at 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.
- at 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.
+
+ at 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
+ at param[in] space_id tablespace identifier
+ at param[in] n_ext number of extents to reserve
+ at param[in] alloc_type page reservation type (FSP_BLOB, etc)
+ at param[in,out] mtr the mini transaction
+ at param[in] n_pages for small tablespaces (tablespace size is
+ less than FSP_EXTENT_SIZE), number of free
+ pages to reserve.
+ at 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 @@ fsp_reserve_free_extents(
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 @@ fsp_reserve_free_extents(
<< " rounds: " << rounds
<< " total_reserved: " << total_reserved << ".";
}
-
goto try_again;
}
@@ -3420,33 +3832,8 @@ fseg_page_is_free(
}
/**********************************************************************//**
-Checks if a single page is free.
- at 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.
+ at 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 6f1ef8c..f66f7b8 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
- at 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 b1d3ab9..66b5da1 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 14e52a9..8c542aa 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
+ at param[in] node ast node to check
+ at 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 5edee71..5faa68b 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
+ at 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
- at 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
+ at 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.
+ at 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
+ at 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 @@ fts_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 @@ fts_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
+ at 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 @@ fts_init_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
- at param[in,out] trx trx handler
- at return true if check certifies auxillary tables are sane false otherwise. */
-bool
-fts_is_corrupt(
+ at 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 89cdcf2..5989aff 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 8abeb63..dee7c59 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.
+ at param[in] trx transaction
+ at param[in] index fts index to search
+ at param[in] flags FTS search mode
+ at param[in] query_str FTS query
+ at param[in] query_len FTS query string len in bytes
+ at param[in,out] result result doc ids
+ at 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 45f0bd9..512fce3 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 @@ rtr_update_mbr_field(
/**************************************************************//**
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 @@ rtr_page_split_and_insert(
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 @@ rtr_page_split_and_insert(
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 @@ rtr_page_split_and_insert(
block, new_block, mtr);
}
+
/* If the new res insert fail, we need to do another split
again. */
if (!rec) {
@@ -1289,9 +1303,12 @@ rtr_page_split_and_insert(
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 26440b5..2c0c5b4 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.
+ at param[in] index rtree index
+ at param[in] block child page in the index
+ at param[in] mtr mtr
+ at param[in] sea_cur search cursor, contains information
+ about parent nodes in search
+ at 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 @@ rtr_get_father_node(
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 @@ rtr_get_father_node(
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 @@ rtr_get_father_node(
|| (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 e12cc31..9615e7f 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.
+ at param[in] thd current session
+ at param[in] var the system variable innodb_support_xa
+ at param[in,out] var_ptr the contents of the variable
+ at 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.
- at param[in] hton InnoDB handlerton
- at param[in] binlog_group_flush true if we got invoked by binlog
-group commit during flush stage, false in other cases.
- at 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.
- at 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.
+ at param[in] thd thread handle, or NULL to query
+ the global innodb_tmpdir.
+ at 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.
+ at 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.
- at 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.
+ at 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".
+ at param[in] algorithm Encryption algorithm to check
+ at 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
+ at param[in] option encryption option
+ at param[in/out] encryption The encryption algorithm
+ at 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
+ at param[in] option Encryption option
+ at param[out] encryption The encryption algorithm
+ at 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.
+ at param[in] trx InnoDB transaction, or NULL
+ at param[in] id identifier to quote
+ at 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.
+ at 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_init(
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_init(
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_init(
/* 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_init(
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.
- at param[in] hton InnoDB handlerton
- at param[in] binlog_group_flush true if we got invoked by binlog
-group commit during flush stage, false in other cases.
- at 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.
+ at param[out] norm_name Normalized name, null-terminated.
+ at param[in] name Name to normalize.
+ at 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
- at param[in] locked true if innobase_share_mutex is held
+ at 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
- at 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 @@ ha_innobase::write_row(
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 @@ ha_innobase::update_row(
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);
+
+ int err;
+ err = convert_error_code_to_mysql(
+ DB_FORCED_ABORT, 0, m_user_thd);
- my_error(ret, MYF(0));
+ 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 @@ ha_innobase::ft_read(
/* 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 @@ ha_innobase::ft_read(
innobase_fts_store_docid(
table, ranking->doc_id);
}
+#endif
table->status= 0;
return(0);
}
@@ -11241,9 +11535,7 @@ ha_innobase::ft_read(
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
+ at param[in] table InnoDB table
+ at param[in] field MySQL field
+ at 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 @@ create_table_info_t::create_table_def()
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 @@ create_table_info_t::create_table_def()
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 @@ create_table_info_t::create_table_def()
}
}
+ /** 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 @@ create_table_info_t::create_table_def()
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 @@ create_table_info_t::create_table_def()
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 @@ create_table_info_t::create_table_def()
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 @@ create_table_info_t::create_table_def()
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,20 +13183,91 @@ create_table_info_t::create_option_tablespace_is_valid()
return(true);
}
-/** 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
-here unless innodb_strict_mode is on. With strict mode, this function
-will report each problem it finds using a custom message with error
-code ER_ILLEGAL_HA_CREATE_OPTION, not its built-in message.
- at return NULL if valid, string name of bad option if not. */
-const char*
-create_table_info_t::create_options_are_invalid()
+#ifdef MYSQL_COMPRESSION
+/** Validate the COPMRESSION option.
+ at return true if valid, false if not. */
+bool
+create_table_info_t::create_option_compression_is_valid()
{
- bool has_key_block_size = (m_create_info->key_block_size != 0);
+ dberr_t err;
+ Compression compression;
- const char* ret = NULL;
- enum row_type row_format = m_create_info->row_type;
+ 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
+here unless innodb_strict_mode is on. With strict mode, this function
+will report each problem it finds using a custom message with error
+code ER_ILLEGAL_HA_CREATE_OPTION, not its built-in message.
+ at return NULL if valid, string name of bad option if not. */
+const char*
+create_table_info_t::create_options_are_invalid()
+{
+ bool has_key_block_size = (m_create_info->key_block_size != 0);
+
+ const char* ret = NULL;
+ enum row_type row_format = m_create_info->row_type;
ut_ad(m_thd != NULL);
ut_ad(m_create_info != NULL);
@@ -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 @@ create_table_info_t::innobase_table_flags()
}
//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 @@ create_table_info_t::innobase_table_flags()
"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 @@ create_table_info_t::innobase_table_flags()
} 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 @@ create_table_info_t::innobase_table_flags()
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.
- at 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
@@ -16573,49 +16979,144 @@ ha_innobase::disable_indexes(
/* Disable index only for intrinsic table. Behavior for all other
table continue to remain same. */
- if (dict_table_is_intrinsic(m_prebuilt->table)) {
- ut_ad(mode == HA_KEY_SWITCH_ALL);
- for (dict_index_t* index
- = UT_LIST_GET_FIRST(m_prebuilt->table->indexes);
- index != NULL;
- index = UT_LIST_GET_NEXT(indexes, index)) {
+ if (dict_table_is_intrinsic(m_prebuilt->table)) {
+ ut_ad(mode == HA_KEY_SWITCH_ALL);
+ for (dict_index_t* index
+ = UT_LIST_GET_FIRST(m_prebuilt->table->indexes);
+ index != NULL;
+ index = UT_LIST_GET_NEXT(indexes, index)) {
+
+ /* InnoDB being clustered index we can't disable/enable
+ clustered index itself. */
+ if (dict_index_is_clust(index)) {
+ continue;
+ }
+
+ index->allow_duplicates = true;
+ }
+ error = 0;
+ }
+
+ return(error);
+}
+
+/*
+Updates index cardinalities of the table, based on random dives into
+each index tree. This does NOT calculate exact statistics on the table.
+ at return HA_ADMIN_* error code or HA_ADMIN_OK */
+
+int
+ha_innobase::analyze(
+/*=================*/
+ THD* thd, /*!< in: connection thread handle */
+ HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
+{
+ /* Simply call info_low() with all the flags
+ and request recalculation of the statistics */
+ int ret = info_low(
+ HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
+ true /* this is ANALYZE */);
+
+ if (ret != 0) {
+ return(HA_ADMIN_FAILED);
+ }
+
+ return(HA_ADMIN_OK);
+}
+
+/*****************************************************************//**
+Defragment table.
+ at 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;
+ }
- /* InnoDB being clustered index we can't disable/enable
- clustered index itself. */
- if (dict_index_is_clust(index)) {
- continue;
+ 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;
+ }
}
-
- index->allow_duplicates = true;
+ os_event_destroy(event);
}
- error = 0;
- }
- return(error);
-}
+ if (ret) {
+ break;
+ }
-/*
-Updates index cardinalities of the table, based on random dives into
-each index tree. This does NOT calculate exact statistics on the table.
- at return HA_ADMIN_* error code or HA_ADMIN_OK */
+ if (one_index) {
+ one_index = FALSE;
+ break;
+ }
+ }
-int
-ha_innobase::analyze(
-/*=================*/
- THD* thd, /*!< in: connection thread handle */
- HA_CHECK_OPT* check_opt) /*!< in: currently ignored */
-{
- /* Simply call info_low() with all the flags
- and request recalculation of the statistics */
- int ret = info_low(
- HA_STATUS_TIME | HA_STATUS_CONST | HA_STATUS_VARIABLE,
- true /* this is ANALYZE */);
+ dict_table_close(table, FALSE, FALSE);
- if (ret != 0) {
- return(HA_ADMIN_FAILED);
+ if (ret == 0 && one_index) {
+ ret = ER_NO_SUCH_INDEX;
}
- return(HA_ADMIN_OK);
+ return ret;
}
/**********************************************************************//**
@@ -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
- at param[in] table MySQL TABLE
- at param[in] ib_table InnoDB dict_table_t
- at 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
- at 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);
@@ -20071,140 +20594,47 @@ innodb_stopword_table_validate(
stopword_table_name = value->val_str(value, buff, &len);
- trx = check_trx_exists(thd);
-
- row_mysql_lock_data_dictionary(trx);
-
- /* Validate the stopword table's (if supplied) existence and
- of the right format */
- if (!stopword_table_name
- || fts_valid_stopword_table(stopword_table_name)) {
- *static_cast<const char**>(save) = stopword_table_name;
- ret = 0;
- }
-
- row_mysql_unlock_data_dictionary(trx);
-
- return(ret);
-}
-
-/** Update the system variable innodb_buffer_pool_size using the "saved"
-value. This function is registered as a callback with MySQL.
- at param[in] thd thread handle
- at param[in] var pointer to system variable
- at param[out] var_ptr where the formal string goes
- at param[in] save immediate result from check function */
-static
-void
-innodb_buffer_pool_size_update(
- THD* thd,
- struct st_mysql_sys_var* var,
- void* var_ptr,
- const void* save)
-{
- longlong in_val = *static_cast<const longlong*>(save);
-
- ut_snprintf(export_vars.innodb_buffer_pool_resize_status,
- sizeof(export_vars.innodb_buffer_pool_resize_status),
- "Requested to resize buffer pool.");
-
- os_event_set(srv_buf_resize_event);
-
- ib::info() << export_vars.innodb_buffer_pool_resize_status
- << " (new size: " << in_val << " bytes)";
-}
-
-/** Validate the requested buffer pool size. Also, reserve the necessary
-memory needed for buffer pool resize.
- at param[in] thd thread handle
- at param[in] var pointer to system variable
- at param[out] save immediate result for update function
- at param[in] value incoming string
- at 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();
+ trx = check_trx_exists(thd);
- 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);
+ row_mysql_lock_data_dictionary(trx);
+
+ /* Validate the stopword table's (if supplied) existence and
+ of the right format */
+ if (!stopword_table_name
+ || fts_valid_stopword_table(stopword_table_name)) {
+ *static_cast<const char**>(save) = stopword_table_name;
+ ret = 0;
}
- ulint requested_buf_pool_size
- = buf_pool_size_align(static_cast<ulint>(intbuf));
+ row_mysql_unlock_data_dictionary(trx);
- *static_cast<longlong*>(save) = requested_buf_pool_size;
+ return(ret);
+}
- if (srv_buf_pool_size == requested_buf_pool_size) {
- buf_pool_mutex_exit_all();
- /* nothing to do */
- return(0);
- }
+/** Update the system variable innodb_buffer_pool_size using the "saved"
+value. This function is registered as a callback with MySQL.
+ at param[in] thd thread handle
+ at param[in] var pointer to system variable
+ at param[out] var_ptr where the formal string goes
+ at param[in] save immediate result from check function */
+static
+void
+innodb_buffer_pool_size_update(
+ THD* thd,
+ struct st_mysql_sys_var* var,
+ void* var_ptr,
+ const void* save)
+{
+ longlong in_val = *static_cast<const longlong*>(save);
- srv_buf_pool_size = requested_buf_pool_size;
- buf_pool_mutex_exit_all();
+ ut_snprintf(export_vars.innodb_buffer_pool_resize_status,
+ sizeof(export_vars.innodb_buffer_pool_resize_status),
+ "Requested to resize buffer pool.");
- 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));
- }
+ os_event_set(srv_buf_resize_event);
- return(0);
+ ib::info() << export_vars.innodb_buffer_pool_resize_status
+ << " (new size: " << in_val << " bytes)";
}
/*************************************************************//**
@@ -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.
+ at 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.
+ at param[in] foreign foreign key information
+ at param[in] update updated parent vector.
+ at param[in] col_no column position of the table
+ at 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
- at 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
- at param[in] in_purge whether this is called by purge
+ at param[in] thd MySQL thread handle
+ at param[in,out] mysql_table mysql table object
+ at param[in] old_table during ALTER TABLE, this is the old table
+ or NULL.
+ at param[in] parent_update update vector for the parent row
+ at 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.
+ at param[in] thd thread handle
+ at param[in] var pointer to system variable
+ at param[out] save immediate result for update function
+ at param[in] value incoming string
+ at 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 b269675..312584d 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 @@ class ha_innobase: public handler
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 @@ class ha_innobase: public handler
@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 @@ class ha_innobase: public handler
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 @@ class ha_innobase: public handler
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 @@ class ha_innobase: public handler
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
+ at param thd user thread
+ at retval 0 the user thread is not a replication slave thread
+ at 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
+ at param thd user thread
+ at retval 0 the user thread is not running a non-transactional update
+ at 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
+ at param thd user thread
+ at 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.
+ at param thd Thread handle
+ at 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.
+ at param thd Thread handle
+ at 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.
+ at param thd Thread handle
+ at return a durability property. */
+durability_properties thd_get_durability_property(const MYSQL_THD thd);
/** Is strict sql_mode set.
- at param thd Thread object
- at return True if sql_mode has strict mode (all or trans), false otherwise.
-*/
-bool thd_is_strict_mode(const MYSQL_THD thd)
-__attribute__((nonnull));
+ at param thd Thread object
+ at 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.
- at 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
- at 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.
- at 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.
- at return true if the table will use an existing shared general tablespace. */
+ at 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.
+ at param[in] create_info Metadata for the table to create.
+ at 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 @@ class create_table_info_t
/** 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 @@ class create_table_info_t
/** 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
+ at param[in] table the InnoDB table
+ at param[in] field MySQL field
+ at 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
+ at param[in] table InnoDB table
+ at param[in] field MySQL field
+ at 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
- at 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
- at param[in] table MySQL TABLE
- at param[in] ib_table InnoDB dict_table_t
- at 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.
- at 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
- at 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
- at param[in] table InnoDB table
- at param[in] field MySQL field
- at 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
+ at 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 855090a..5fd02df 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 @@ ha_innopart::open(
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.
+ at param[in] thd user thread handle
+ at param[in] to pointer to the current element in an array of
+pointers to lock structs
+ at param[in] lock_type lock type to store in 'lock'; this may also be
+TL_IGNORE
+ at 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 0a6bfe0..8caa9cd 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 @@ class Ha_innopart_share : public Partition_share
/** 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 @@ class ha_innopart:
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 @@ class ha_innopart:
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 @@ class ha_innopart:
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 5f421d4..5904045 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 @@ innobase_find_fk_index(
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.
+ at param[in] col_name column name
+ at param[in] table table
+ at param[in] s_cols list of stored columns
+ at 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.
+ at param[in] foreign Foriegn key constraing information
+ at param[in] table table to which the foreign key objects
+to be added
+ at param[in] s_cols list of stored column information in the table.
+ at 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
+ at param[in] ha_alter_info alter table info
+ at param[in] table_share TABLE_SHARE
+ at param[in] table table object
+ at param[in] col_names column names, or NULL to use
+table->col_names
+ at param[in] drop_index indexes to be dropped
+ at param[in] n_drop_index size of drop_index
+ at param[out] add_fk foreign constraint added
+ at param[out] n_add_fk number of foreign constraints
+added
+ at param[in] trx user transaction
+ at 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 @@ innobase_check_index_keys(
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 @@ innobase_create_key_defs(
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 @@ innobase_build_col_map(
+ 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".
+ at param[in] ha_alter_info Data used during in-place alter
+ at param[in] old_table MySQL table as it is before the ALTER operation
+ at param[in] num_v_dropped number of virtual column dropped
+ at 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,11 +4986,22 @@ prepare_inplace_alter_table_dict(
}
}
- if (!ctx->new_table->fts
- && innobase_fulltext_exist(altered_table)) {
- ctx->new_table->fts = fts_create(
- ctx->new_table);
- ctx->new_table->fts->doc_col = fts_doc_id_col;
+ 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(
+ ctx->new_table);
+ ctx->new_table->fts->doc_col = fts_doc_id_col;
}
/* Check if we need to update mtypes of legacy GIS columns.
@@ -4784,6 +5026,15 @@ prepare_inplace_alter_table_dict(
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 @@ prepare_inplace_alter_table_dict(
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 @@ prepare_inplace_alter_table_dict(
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.
+ at param[in] altered_table mysql table object
+ at param[in] table innodb table object
+ at param[out] s_cols list of stored column
+ at 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 @@ ha_innobase::prepare_inplace_alter_table(
}
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 @@ ha_innobase::prepare_inplace_alter_table(
}
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 @@ ha_innobase::prepare_inplace_alter_table(
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 @@ ha_innobase::prepare_inplace_alter_table(
rename_index[i] = index;
}
}
+#endif /* MYSQL_RENAME_INDEX */
n_add_fk = 0;
@@ -5929,6 +6232,10 @@ ha_innobase::prepare_inplace_alter_table(
& 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 @@ ha_innobase::prepare_inplace_alter_table(
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 @@ ha_innobase::prepare_inplace_alter_table(
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 @@ ha_innobase::prepare_inplace_alter_table(
}
- /* 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 @@ ha_innobase::prepare_inplace_alter_table(
ha_alter_info, altered_table, table)) {
DBUG_RETURN(true);
}
- */
+#endif /* MYSQL_VIRTUAL_COLUMNS */
DBUG_RETURN(false);
}
@@ -6020,8 +6337,6 @@ ha_innobase::prepare_inplace_alter_table(
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 @@ ha_innobase::prepare_inplace_alter_table(
/* 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 @@ ha_innobase::prepare_inplace_alter_table(
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 @@ ha_innobase::prepare_inplace_alter_table(
add_fts_doc_id_idx));
}
+/** Check that the column is part of a virtual index(index contains
+virtual column) in the table
+ at param[in] table Table containing column
+ at param[in] col column to be checked
+ at 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.
+ at param[in] altered_table TABLE object for new version of table.
+ at param[in] ha_alter_info Structure describing changes to be done
+ by ALTER TABLE and holding data used
+ during in-place alter.
+ at param[in] table table being altered
+ at 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 @@ ha_innobase::inplace_alter_table(
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 @@ ha_innobase::inplace_alter_table(
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 @@ ha_innobase::inplace_alter_table(
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 @@ ha_innobase::inplace_alter_table(
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.
+ at param[in] table table object
+ at param[in] col_no column number of the column which is to be checked
+ at param[in] is_v if this is a virtual column
+ at retval true column exists
+ at 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 @@ rollback_inplace_alter_table(
}
}
+ /* 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 @@ innobase_rename_columns_try(
@param table_name Table name in MySQL
@param nth_col 0-based index of the column
@param new_len new column length, in bytes
+ at 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.
- at param[in] table table object
- at param[in] col_no column number of the column which is to be checked
- at param[in] is_v if this is a virtual column
- at retval true column exists
- at 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 @@ ha_innobase::commit_inplace_alter_table(
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 @@ ha_innobase::commit_inplace_alter_table(
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 @@ ha_innobase::commit_inplace_alter_table(
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 @@ ha_innobase::commit_inplace_alter_table(
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 @@ conveniance. */
}
};
+#ifdef MYSQL_INNODB_PARTITIONING
+
+/** Check if supported inplace alter table.
+ at param[in] altered_table Altered MySQL table.
+ at param[in] ha_alter_info Information about inplace operations to do.
+ at 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().
+ at param[in] altered_table TABLE object for new version of table.
+ at param[in] ha_alter_info Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+ at retval true Failure.
+ at 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().
+ at param[in] altered_table TABLE object for new version of table.
+ at param[in] ha_alter_info Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+ at retval true Failure.
+ at 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).
+ at param[in] altered_table TABLE object for new version of table.
+ at param[in] ha_alter_info Structure describing changes to be done
+by ALTER TABLE and holding data used during in-place alter.
+ at param[in] commit true => Commit, false => Rollback.
+ at retval true Failure.
+ at 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 3d7124c..524cbc8 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 bfdaefc..71aa7be 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
- at 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.
- at 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 @@ ibuf_insert_low(
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 @@ ibuf_insert_low(
#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 @@ ibuf_merge_or_delete_for_page(
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 127f8e1..ec02feb 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.
+ at param[in] crsr InnoDB Cursor
+ at 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 e350e01..c177f23 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 64ffa89..a1887c3 100644
--- a/storage/innobase/include/btr0bulk.h
+++ b/storage/innobase/include/btr0bulk.h
@@ -260,7 +260,7 @@ class PageBulk
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 659944f..1265903 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 4fd7681..5f7c39b 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 734b33e..19c2198 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 6e147ce..c4bc107 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.
+ at 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.
- at 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 bd75c7a..bf77997 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.
- at 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 684c378..9405251 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 1f8f23e..eb13c3b 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 1d38c67..4008379 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).
+ at param[in] thd thread handle
+ at param[in] var pointer to system variable
+ at param[out] var_ptr where the formal string goes
+ at 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 f2ec11f..9c97a51 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 24b0a79..5537d70 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"
+ at param[in,out] field field */
+UNIV_INLINE
+spatial_status_t
+dfield_get_spatial_status(
+ const dfield_t* field);
+
+/** Sets spatial status for "external storage"
+ at param[in,out] field field
+ at 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 c6c155c..dc51735 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"
+ at 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"
+ at param[in,out] field field
+ at 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 5297d6b..32f9117 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 7915d69..f9ef39f 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
+ at param[in] local_fk_set set of foreign key objects, to be added to
+the dictionary tables
+ at param[in] table table to which the foreign key objects in
+local_fk_set belong to
+ at 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 0000000..eb2a6e6
--- /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
+
+*****************************************************************************/
+
+/**************************************************//**
+ at 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.
+ at 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.
+ at 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 af7b91f..5022245 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.
+ at 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
+ at 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.
+ at 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).
+ at param[in] id Space ID to check
+ at 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.
- at param[in] space Tablespace ID to search for.
+ at 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.
+ at param[in] name Tablespace name to search for.
+ at return the tablespace ID. */
+ulint
+dict_space_get_id(
+ const char* name);
+
+/** Free the virtual column template
+ at 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.
+ at param[in] table InnoDB table
+ at 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 9aa25b0..1a038d4 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.
+ at 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.
+ at 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).
+ at param[in] id Space ID to check
+ at 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
+ at 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.
+ at param[in] table InnoDB table
+ at 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 8e62022..6d01c38 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.
+ at param[in] space_id Tablespace ID
+ at return First filepath (caller must invoke ut_free() on it)
+ at 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 98ce7d3..4fac064 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.
+ at param[in] table table
+ at 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
+ at 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.
+ at 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.
+ at 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 @@ struct dict_table_t {
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 @@ struct dict_table_t {
#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
- at return col_spatial_status */
+ at 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 40f254b..8941b39 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.
+ at 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.
+ at param[in] index index to be updated
+ at param[in] last_update timestamp of the stat
+ at param[in] stat_name name of the stat
+ at param[in] stat_value value of the stat
+ at param[in] sample_size n pages sampled or NULL
+ at param[in] stat_description description of the stat
+ at 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.
+ at 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 e04d9ab5a..50c2591 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).
+ at param[in] thd thread handle
+ at param[in] var pointer to system variable
+ at param[out] var_ptr where the formal string goes
+ at 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 5e6e562..ae002dd 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 7e2995c..3126c8e 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 @@ class dyn_buf_t {
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 @@ class dyn_buf_t {
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 @@ class dyn_buf_t {
/**
@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 @@ class dyn_buf_t {
/**
@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 @@ class dyn_buf_t {
/**
@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 @@ class dyn_buf_t {
/**
@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 @@ class dyn_buf_t {
@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 @@ class dyn_buf_t {
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 @@ class dyn_buf_t {
/**
@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 @@ class dyn_buf_t {
/**
@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 1a91aee..65ca4de 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.,
*****************************************************************************/
/**************************************************//**
- at file include/fil0fil.h
+ at 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 d04355c..4171bed 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.
+ at param[in] filepath asbosolute / relative or simply file name
+ at retvalue true if it is intermediate file
+ at 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.
+ at param[in] id tablespace ID
+ at 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.
- at param[in] id tablespace ID
- at 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.
- at 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.
- at 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.
+ at param[in] lsn flushed LSN
+ at 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 @@ class FilSpace
};
#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
+ at 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
- at return whether the operation succeeded */
-bool
+ at 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
- at param[in] space Space ID of tablespace for which to set
- at param[in] algorithm Text representation of the algorithm
+/** Set the compression type for the tablespace of a table
+ at param[in] table Table that should be compressesed
+ at 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));
-/**
- at param[in] space_id Space ID to check
+/** Get the compression type for the tablespace
+ at 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
+ at param[in] space Space ID of tablespace for which to set
+ at param[in] algorithm Encryption algorithm
+ at param[in] key Encryption key
+ at param[in] iv Encryption iv
+ at 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));
+
+/**
+ at 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.
+ at 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.
- at param[in] lsn flushed LSN
- at 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 a08ebff..83aa370 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 @@ class Datafile {
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 @@ class Datafile {
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 @@ class Datafile {
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 @@ class Datafile {
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 @@ class Datafile {
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 @@ class Datafile {
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 @@ class Datafile {
@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 @@ class Datafile {
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 @@ class Datafile {
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 @@ class Datafile {
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 @@ class RemoteDatafile : public Datafile
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 17be27a..3709c4a 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.
+ at param[in/out] key key
+ at param[in/out] iv iv
+ at param[in] encryption_info encrytion info.
+ at 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.
+ at param[in] fsp_flags tablespace flags
+ at param[in/out] key tablespace key
+ at param[in/out] iv tablespace iv
+ at param[in] page first page of a tablespace
+ at 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.
+ at param[in] fsp_flags tablespace flags
+ at param[in] page first page of a tablespace
+ at 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.
+ at param[in] space tablespace
+ at param[in] encrypt_info buffer for re-encrypt key.
+ at param[in,out] mtr mini-transaction
+ at 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.
- at 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.
+
+ at 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
+ at param[in] space_id tablespace identifier
+ at param[in] n_ext number of extents to reserve
+ at param[in] alloc_type page reservation type (FSP_BLOB, etc)
+ at param[in,out] mtr the mini transaction
+ at param[in] n_pages for small tablespaces (tablespace size is
+ less than FSP_EXTENT_SIZE), number of free
+ pages to reserve.
+ at 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.
+ at 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 */
+/*********************************************************************//**
+ at 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 e204ac3..475dd23 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.
+ at 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
- at 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.
+ at param[in] page_size page size
+ at 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 5fdb12a..603c71b 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 @@ class Tablespace {
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 @@ class Tablespace {
/** 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 42778f7..226d53e 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 @@ class SysTablespace : public Tablespace
* ((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 @@ class SysTablespace : public Tablespace
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.
- at param[in] id Space ID to check
- at 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 33f630a..73fd634 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 f0f00a4..87b7cf7 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
+ at param[in] node ast node to check
+ at 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 210b9b7..2d25647 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.
+ at param[in] trx transaction
+ at param[in] index fts index to search
+ at param[in] flags FTS search mode
+ at param[in] query_str FTS query
+ at param[in] query_len FTS query string len in bytes
+ at param[in,out] result result doc ids
+ at 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
+ at 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
- at param[in,out] trx trx handler
- at return true if check certifies auxillary tables are sane false otherwise. */
-bool
-fts_is_corrupt(
+ at 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 f7a2d2c..1fd33c2 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 9de3be2..fa2cdd4 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 ab04a70..0b8b8b0 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 316cab8..436374f 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.
+ at param[in] offsets work area for the return value
+ at param[in] index rtree index
+ at param[in] block child page in the index
+ at param[in] mtr mtr
+ at param[in] sea_cur search cursor, contains information
+ about parent nodes in search
+ at 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 11c12c4..15a99dd 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 9bf8cd2..837c377f 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.
+ at param[in] thd thread handle, or NULL to query
+ the global innodb_tmpdir.
+ at 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 c4d8383..f3fd5e9 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.
- at 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 84050f3..eb554e0 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.
+ at param[in] table table to lock
+ at param[in,out] trx transaction
+ at param[in] mode LOCK_X or LOCK_S
+ at 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 8941a13..6c61f07 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
+ at param[in] trx trx to test the lock
+ at param[in] space space id for the page
+ at 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.
+ at param[in] block page to be discarded
+ at 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 06573d2..0b2ab1b 100644
--- a/storage/innobase/include/lock0priv.h
+++ b/storage/innobase/include/lock0priv.h
@@ -729,20 +729,23 @@ class RecLock {
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 @@ class RecLock {
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 @@ class RecLock {
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 @@ class RecLock {
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 e67eef4..c1f2570 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 caf4976..a53f877 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 85b326e..bd71186 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 07e2313..4d32e2e 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 88c88cf..ece4a37 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 72791e2..f8fdb53 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 d20a164..3b4109e 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 07aa08e..4015fe3 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 d3aa191..4a1d867 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 6c61f8d..b3d9b05 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 1368176..7ac429c 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 651f7b5..1f1c460 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 5aa1843..5e36cfc 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 @@ class IORequest {
/** @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 @@ class IORequest {
/** @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 @@ class IORequest {
/** @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 @@ class IORequest {
/** 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 @@ class IORequest {
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 @@ class IORequest {
/** @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 @@ class IORequest {
/** @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 @@ class IORequest {
/** 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 '\'.
- at 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 ec90548..74d0b2c 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
+ at 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 32fd1c7..0be2fa8 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 58be8b0..c111717 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 8d1e5b1..3bb6221 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 5dabcf2..fe56468 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 20643b6..7b5df3d 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
+ at param[in] index dict index object
+ at param[in] entry entry for the index
+ at 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.
- at param ptr pointer to an uncompressed page frame
- at param page_zip compressed page descriptor
- at 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.
- at param ptr pointer to an uncompressed page frame
- at param page_zip compressed page descriptor
- at 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.
- at param[in] current_algo current checksum algorithm
- at param[in] page_checksum page valid checksum
- at param[in] space_id tablespace id
- at 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 cbb3660..9963fe0 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 f52b35c..7e153d0 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
@@ -4