You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
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.
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';
0 commit comments