[MDEV-8069] DROP or rebuild of a large table may lock up InnoDB Created: 2015-04-28 Updated: 2023-11-27 Resolved: 2020-06-10 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Storage Engine - InnoDB, Storage Engine - XtraDB |
| Affects Version/s: | 10.0.16, 10.1.34, 10.2.27 |
| Fix Version/s: | 10.5.4 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Stoykov (Inactive) | Assignee: | Eugene Kosov (Inactive) |
| Resolution: | Fixed | Votes: | 5 |
| Labels: | affects-tests, drop-table-optimiation, upstream, xtradb | ||
| Environment: |
Red Hat Enterprise Linux |
||
| Issue Links: |
|
||||||||||||||||||||||||||||||||||||||||||||||||
| Sprint: | 10.3.1-1 | ||||||||||||||||||||||||||||||||||||||||||||||||
| Description |
|
DROP DATABASE IF EXSITS executed on database with more that several thousand tables and over several TBs data in it is unreasonably slow. Crash description:
Please do not ignore the Feature Request for optimizing the DROP DATABASE operation, even this ticket is marked as a bug. |
| Comments |
| Comment by Stoykov (Inactive) [ 2015-04-29 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
short update: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2015-05-05 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Lets consider the transactional way. If we have log record for DROP_DATABASE then it is enough to write that log record with database name to redo log. This is because if we crash on middle of dropping database at recovery we might need to redo the operation. If we do not have log record for DROP_DATABASE we at least have log record for DROP_TABLE. In this case we need to iterate all tables on database and for each table write DROP_TABLE log record (for similar crash recovery redo). | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2015-05-05 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
http://bugs.mysql.com/bug.php?id=51325 | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2015-05-24 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
After some experiments. Here is what found. If database is created containing 999 small tables and one big table, I can repeat slow execution time if contents of the table is on buffer pool. If I create database, shutdown, restart and then drop database, I could not repeat. If I create database, shutdown, restart, select, and then drop database still can't really repeat.
Big table on this test was:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2017-03-24 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
In MySQL 10.x, row_drop_table_for_mysql() (which is executing as part of DROP TABLE or DROP DATABASE) contains a non-ACID hack, the ‘background DROP TABLE queue’. Under certain circumstances, it is possible that the table will not be dropped immediately. I think that the only scenarios under which the DROP TABLE queue can kick in is when there are FOREIGN KEY constraints associated with the table, and another session is causing an access to this table via FOREIGN KEY constraints. Another case is the error handling for CREATE TABLE…SELECT, but I think that it is unlikely here. In MySQL, WL#6049 should eventually fix the FOREIGN KEY problem by acquiring proper meta-data locks for DML operations that may affect FOREIGN KEY tables. As far as I understand, it is planned to be fixed in MySQL 8.0. This is not the only problem with the current-form DROP TABLE. If we implement a transactional data dictionary (MDEV-11655), in the DROP operations we would introduce a ‘post-commit’ step that actually purges the data (deletes files or frees pages in shared tablespaces) after the operation has been committed, while not holding any locks. This would also require the removal of the non-ACID ‘background DROP TABLE queue’ hack. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2017-03-24 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
My current hypothesis is that row_drop_table_for_mysql() waited for more than 10 minutes for an exclusive dict_operation_lock, and finally the InnoDB watchdog kicked in, aborting the process. This could be a starvation problem. InnoDB purge and rollback are acquiring shared dict_operation_lock. Maybe if there is constantly at least one S-lock holder, the X-lock request will never be fulfilled? I was suspecting that InnoDB rollback would be holding dict_operation_lock in shared mode for the whole duration of the rollback, but that is not the case in MariaDB 10.0. The rw-lock is being acquired and released for each undo log record that is being processed. The trick ALTER TABLE…DISCARD TABLESPACE is a good way of ensuring that rollback and purge immediately stop costly key lookups on the table. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2017-06-01 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Test 1: TPC-C database. I created TPC-C database with 100 warehouses using https://github.com/Percona-Lab/tpcc-mysql
Similarly I created LinkBench database https://github.com/facebookarchive/linkbench. I used LinkBench measure as workload while doing drop tests. For linktable I removed the partitioning. First table to be removed i.e. stock2 is about 34G. First test is as follows:
I could not repeat any crash, mutex wait in:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2017-06-01 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Test 2 while running LinkBench measure workload drop linktable (used by workload) where linktable is about 80G. Still I do not see any performance problems or crashes:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2017-06-05 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Last test dropping a database with size ~230G and 20003 tables while running LinkBench measure. Still can't repeat any crash or significant slowness,
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2017-06-05 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Firstly, is this repeatable with more recent version of MariaDB? If it is, could you please provide exact steps to repeat ad you can see I could not repeat the problem. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Jan Lindström (Inactive) [ 2017-06-07 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Could not repeat the problem with 10.0.16. I used two ~100G LinkBench databases with addition of 10K generated small tables for both databases. While running LinkBench measure on other db, dropping the other db naturally took quite long ~6minutes, but dropping the same db as workload used it was only ~1minute. No errors found on error log and no hangs or assertions seen. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Geoff Montee (Inactive) [ 2017-09-11 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Hi julien.fritsch, No. The support issue has been closed because progress on this bug is being tracked in Jira. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2018-10-12 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I believe that the issue is that on a fragmented file system, deleting a large file is taking a lot of time. Several years ago, there was a patch contributed to MySQL that would replace the unlink() system call with a series of system calls that would shrink the file piece by piece. I am not sure if that is a sensible approach. However, I am sure that InnoDB should not be holding any mutexes while deleting the file. I see that both row_drop_table_for_mysql() and row_discard_tablespace() are holding both dict_sys->mutex and dict_operation_lock exclusively while calling fil_delete_tablespace(). I believe that a reasonable fix would be as follows:
This is technically doable in MariaDB Server 10.3, and also starting with 10.2.19 if the A more proper solution would involve writing undo log records for "delete file" operations, to be processed by rollback (rolling back CREATE TABLE) or purge (cleaning up after committing DROP TABLE). This cannot be done in a GA release, because it involves changing the InnoDB undo log format. Then it would be something like this:
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2018-12-21 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I posted some review remarks to PR#1021 with ideas how to fix this. It seems doable in 10.2 already. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2019-02-08 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
| ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2020-01-28 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
MySQL Bug #91977 could report the same problem. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2020-05-04 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
There are two issues affecting DROP or rebuild operations of large partitions, tables or databases. (Tables or partitions are internally dropped as part of operations that rebuild the table or partition: TRUNCATE and some forms of OPTIMIZE or ALTER TABLE, sometimes even CREATE INDEX or DROP INDEX.) The problem reported in this ticket is that the InnoDB data dictionary cache (dict_sys) is being locked while the data file is being deleted, and deleting a large data file may take a lot of time, especially for a fragmented data file. A related problem affects not only dropping or rebuilding entire tables or partitions, but also DROP INDEX operations that are executed in-place: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2020-05-20 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
InnoDB is invoking unlink() to delete the data file while holding some mutexes. This must be fixed as part of this ticket. On some file systems (most notably, on Linux), unlink() of a large file can block any concurrent usage of the entire file system. A workaround for this may be implemented in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2020-05-26 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
I think that we should try to rely on delete-on-close semantics. That is, copy the handle to the to-be-deleted file, hold it open across the deletion, and close the handle after releasing the dict_sys latches. As far as I understand, file system recovery should guarantee that the file be deleted. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Comment by Matthias Leich [ 2020-06-10 ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|