Skip to content

Commit 5eaf0f1

Browse files
committed
Refactor the code that saves, updates and deletes rows from
mysql.innodb_table_stats and mysql.innodb_index_stats to prepare it for being able to rename a table (update the corresponding rows). * Remove the foreign key from innodb_index_stats because it is a source of various deadlocks. Also the absence of FK would allow users to temporarily store some rows in innodb_index_stats that do not have corresponding rows in innodb_table_stats. * When saving table and its indexes stats - save the table stats and each index stat in a separate transaction to avoid deadlocks. The previous mode of operation for saving was: BEGIN; SELECT FOR UPDATE; if not found INSERT; else UPDATE; COMMIT; Which had the flaw that if there was no entry and two concurrent save functions were called, then one of them could get a deadlock, like this: t1: SELECT FOR UPDATE; (returns not found) t2: SELECT FOR UPDATE; (returns not found) t1: INSERT; (hangs, waiting on t2) t2: INSERT; (fails because of a deadlock) Another way of operation would be: BEGIN; INSERT; if duplicate UPDATE; COMMIT; but that could deadlock with a single DELETE of the corresponding entry in the table, like this: t1: INSERT; (returns duplicate) t2: DELETE; (hangs, waiting on t1) t1: UPDATE; (fails because of a deadlock) Another solution would have been to synchronize dict_stats_save() and dict_stats_delete_table_stats() with a simple mutex, but que_eval_sql() does not allow any latches to be held during its execution except dict_sys->mutex. So we change the save of table stats to: BEGIN; INSERT; COMMIT; if duplicate BEGIN; UPDATE; COMMIT; At worse, a row could get deleted after INSERT has returned a duplicate error and before UPDATE executes, but then the UPDATE will be noop because the WHERE clause will match nothing. The effect will be as if the delete executed after the end of the save operation. * When deleting stats, delete the table and the index stats in separate transactions.
1 parent 1274ab0 commit 5eaf0f1

10 files changed

Lines changed: 426 additions & 514 deletions

mysql-test/r/lowercase_table4.result

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,6 @@ Create Table CREATE TABLE `Table2` (
3030
) ENGINE=InnoDB DEFAULT CHARSET=latin1
3131
SELECT * FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS;
3232
CONSTRAINT_CATALOG def
33-
CONSTRAINT_SCHEMA mysql
34-
CONSTRAINT_NAME innodb_index_stats_ibfk_1
35-
UNIQUE_CONSTRAINT_CATALOG def
36-
UNIQUE_CONSTRAINT_SCHEMA mysql
37-
UNIQUE_CONSTRAINT_NAME PRIMARY
38-
MATCH_OPTION NONE
39-
UPDATE_RULE RESTRICT
40-
DELETE_RULE RESTRICT
41-
TABLE_NAME innodb_index_stats
42-
REFERENCED_TABLE_NAME innodb_table_stats
43-
CONSTRAINT_CATALOG def
4433
CONSTRAINT_SCHEMA test
4534
CONSTRAINT_NAME fk1
4635
UNIQUE_CONSTRAINT_CATALOG def
@@ -100,17 +89,6 @@ Create Table CREATE TABLE `Customer` (
10089
) ENGINE=InnoDB DEFAULT CHARSET=latin1
10190
SELECT * FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS;
10291
CONSTRAINT_CATALOG def
103-
CONSTRAINT_SCHEMA mysql
104-
CONSTRAINT_NAME innodb_index_stats_ibfk_1
105-
UNIQUE_CONSTRAINT_CATALOG def
106-
UNIQUE_CONSTRAINT_SCHEMA mysql
107-
UNIQUE_CONSTRAINT_NAME PRIMARY
108-
MATCH_OPTION NONE
109-
UPDATE_RULE RESTRICT
110-
DELETE_RULE RESTRICT
111-
TABLE_NAME innodb_index_stats
112-
REFERENCED_TABLE_NAME innodb_table_stats
113-
CONSTRAINT_CATALOG def
11492
CONSTRAINT_SCHEMA test
11593
CONSTRAINT_NAME product_order_ibfk_1
11694
UNIQUE_CONSTRAINT_CATALOG def

mysql-test/suite/funcs_1/r/is_key_column_usage.result

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,8 +100,6 @@ def mysql PRIMARY def mysql innodb_index_stats database_name
100100
def mysql PRIMARY def mysql innodb_index_stats table_name
101101
def mysql PRIMARY def mysql innodb_index_stats index_name
102102
def mysql PRIMARY def mysql innodb_index_stats stat_name
103-
def mysql innodb_index_stats_ibfk_1 def mysql innodb_index_stats database_name
104-
def mysql innodb_index_stats_ibfk_1 def mysql innodb_index_stats table_name
105103
def mysql PRIMARY def mysql innodb_table_stats database_name
106104
def mysql PRIMARY def mysql innodb_table_stats table_name
107105
def mysql PRIMARY def mysql ndb_binlog_index epoch

mysql-test/suite/funcs_1/r/is_table_constraints.result

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,6 @@ def mysql PRIMARY mysql help_topic
7070
def mysql name mysql help_topic
7171
def mysql PRIMARY mysql host
7272
def mysql PRIMARY mysql innodb_index_stats
73-
def mysql innodb_index_stats_ibfk_1 mysql innodb_index_stats
7473
def mysql PRIMARY mysql innodb_table_stats
7574
def mysql PRIMARY mysql ndb_binlog_index
7675
def mysql PRIMARY mysql plugin

mysql-test/suite/funcs_1/r/is_table_constraints_mysql.result

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ def mysql PRIMARY mysql help_relation PRIMARY KEY
1919
def mysql name mysql help_topic UNIQUE
2020
def mysql PRIMARY mysql help_topic PRIMARY KEY
2121
def mysql PRIMARY mysql host PRIMARY KEY
22-
def mysql innodb_index_stats_ibfk_1 mysql innodb_index_stats FOREIGN KEY
2322
def mysql PRIMARY mysql innodb_index_stats PRIMARY KEY
2423
def mysql PRIMARY mysql innodb_table_stats PRIMARY KEY
2524
def mysql PRIMARY mysql ndb_binlog_index PRIMARY KEY

mysql-test/suite/funcs_1/r/is_table_constraints_mysql_embedded.result

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ def mysql PRIMARY mysql help_relation PRIMARY KEY
1919
def mysql name mysql help_topic UNIQUE
2020
def mysql PRIMARY mysql help_topic PRIMARY KEY
2121
def mysql PRIMARY mysql host PRIMARY KEY
22-
def mysql innodb_index_stats_ibfk_1 mysql innodb_index_stats FOREIGN KEY
2322
def mysql PRIMARY mysql innodb_index_stats PRIMARY KEY
2423
def mysql PRIMARY mysql innodb_table_stats PRIMARY KEY
2524
def mysql PRIMARY mysql ndb_binlog_index PRIMARY KEY
@@ -55,7 +54,6 @@ def mysql PRIMARY mysql help_relation PRIMARY KEY
5554
def mysql name mysql help_topic UNIQUE
5655
def mysql PRIMARY mysql help_topic PRIMARY KEY
5756
def mysql PRIMARY mysql host PRIMARY KEY
58-
def mysql innodb_index_stats_ibfk_1 mysql innodb_index_stats FOREIGN KEY
5957
def mysql PRIMARY mysql innodb_index_stats PRIMARY KEY
6058
def mysql PRIMARY mysql innodb_table_stats PRIMARY KEY
6159
def mysql PRIMARY mysql ndb_binlog_index PRIMARY KEY

mysql-test/suite/innodb/r/innodb-system-table-view.result

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,8 @@ INDEX_ID NAME POS
1919
14 POS 1
2020
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
2121
ID FOR_NAME REF_NAME N_COLS TYPE
22-
mysql/innodb_index_stats_ibfk_1 mysql/innodb_index_stats mysql/innodb_table_stats 2 0
2322
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
2423
ID FOR_COL_NAME REF_COL_NAME POS
25-
mysql/innodb_index_stats_ibfk_1 database_name database_name 0
26-
mysql/innodb_index_stats_ibfk_1 table_name table_name 1
2724
SELECT count(*) FROM INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS;
2825
count(*)
2926
7
@@ -36,12 +33,9 @@ FOREIGN KEY (parent_id) REFERENCES parent(id)
3633
ON DELETE CASCADE) ENGINE=INNODB;
3734
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
3835
ID FOR_NAME REF_NAME N_COLS TYPE
39-
mysql/innodb_index_stats_ibfk_1 mysql/innodb_index_stats mysql/innodb_table_stats 2 0
4036
test/constraint_test test/child test/parent 1 1
4137
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
4238
ID FOR_COL_NAME REF_COL_NAME POS
43-
mysql/innodb_index_stats_ibfk_1 database_name database_name 0
44-
mysql/innodb_index_stats_ibfk_1 table_name table_name 1
4539
test/constraint_test parent_id id 0
4640
INSERT INTO parent VALUES(1);
4741
SELECT name, num_rows, ref_count
@@ -94,12 +88,9 @@ FOREIGN KEY (id, parent_id) REFERENCES parent(id, newid)
9488
ON DELETE CASCADE) ENGINE=INNODB;
9589
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN;
9690
ID FOR_NAME REF_NAME N_COLS TYPE
97-
mysql/innodb_index_stats_ibfk_1 mysql/innodb_index_stats mysql/innodb_table_stats 2 0
9891
test/constraint_test test/child test/parent 2 1
9992
SELECT * FROM INFORMATION_SCHEMA.INNODB_SYS_FOREIGN_COLS;
10093
ID FOR_COL_NAME REF_COL_NAME POS
101-
mysql/innodb_index_stats_ibfk_1 database_name database_name 0
102-
mysql/innodb_index_stats_ibfk_1 table_name table_name 1
10394
test/constraint_test id id 0
10495
test/constraint_test parent_id newid 1
10596
INSERT INTO parent VALUES(1, 9);

mysql-test/suite/innodb/r/innodb_stats_drop_locked.result

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ innodb_stats_drop_locked CREATE TABLE `innodb_stats_drop_locked` (
2727
) ENGINE=InnoDB DEFAULT CHARSET=latin1 STATS_PERSISTENT=1
2828
DROP TABLE innodb_stats_drop_locked;
2929
Warnings:
30-
Warning 1205 Unable to delete statistics for table test.innodb_stats_drop_locked from mysql.innodb_table_stats or mysql.innodb_index_stats because the rows are locked: Lock wait timeout. They can be deleted later using DELETE FROM mysql.innodb_index_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked'; DELETE FROM mysql.innodb_table_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked';
30+
Warning 1205 Unable to delete statistics for table test.innodb_stats_drop_locked: Lock wait timeout. They can be deleted later using DELETE FROM mysql.innodb_index_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked'; DELETE FROM mysql.innodb_table_stats WHERE database_name = 'test' AND table_name = 'innodb_stats_drop_locked';
3131
SHOW TABLES;
3232
Tables_in_test
3333
COMMIT;

0 commit comments

Comments
 (0)