mirror of
https://github.com/MariaDB/server.git
synced 2025-11-27 05:41:41 +03:00
The server crashes on a SELECT because of space id mismatch. The mismatch happens if the server crashes during an ALTER TABLE. There are actually two cases of inconsistency, and three fixes needed for the InnoDB problems. We have dictionary data (tablespace or table name) in 3 places: (a) The *.frm file is for the old table definition. (b) The InnoDB data dictionary is for the new table definition. (c) The file system did not rename the tablespace files yet. In this fix, we will not care if the *.frm file is in sync with the InnoDB data dictionary and file system. We will concentrate on the mismatch between (b) and (c). Two scenarios have been mentioned in this bug report. The simpler one first: 1. The changes to SYS_TABLES were committed, and MLOG_FILE_RENAME2 records were written in a single mini-transaction commit. The files were not yet renamed in the file system. 2a. The server is killed, without making a log checkpoint. 3a. The server refuses to start up, because replaying MLOG_FILE_RENAME2 fails. I failed to repeat this myself. I repeated step 3a with a saved dataset. The problem seems to be that MLOG_FILE_RENAME2 replay is incorrectly being skipped when there is no page-redo log or MLOG_FILE_NAME record for the old name of the tablespace. FIX#1: Recover the id-to-name mapping also from MLOG_FILE_RENAME2 records when scanning the redo log. It is not necessary to write MLOG_FILE_NAME records in addition to MLOG_FILE_RENAME2 records for renaming tablespace files. The scenario in the original Description involves a log checkpoint: 1. The changes to SYS_TABLES were committed, and MLOG_FILE_RENAME2 records were written in a single mini-transaction commit. 2. A log checkpoint and a server kill was injected. 3. Crash recovery will see no records (other than the MLOG_CHECKPOINT). 4. dict_check_tablespaces_and_store_max_id() will emit a message about a non-found table #sql-ib22*. 5. A mismatch is triggering the assertion failure. In my test, at step 4 the SYS_TABLES root page (0:8) contains these 3 records right before the page supremum: * delete-marked (committed) name=#sql-ib21* record, with space=10. * name=#sql-ib22*, space=9. * name=t1, space=10. space=10 is the rebuilt table (#sql-ib21*.ibd in the file system). space=9 is the old table (t1.ibd in the file system). The function dict_check_tablespaces_and_store_max_id() will enter t1.ibd with space_id=10 into the fil_system cache without noticing that t1.ibd contains space_id=9, because it invokes fil_open_single_table_tablespace() with validate=false. In MySQL 5.6, the space_id from all *.ibd files are being read when the redo log checkpoint LSN disagrees with the FIL_PAGE_FILE_FLUSH_LSN in the system tablespace. This field is only updated during a clean shutdown, after performing the final log checkpoint. FIX#2: dict_check_tablespaces_and_store_max_id() should pass validate=true to fil_open_single_table_tablespace() when a non-clean shutdown is detected, forcing the first page of each *.ibd file to be read. (We do not want to slow down startup after a normal shutdown.) With FIX#2, the SELECT would fail to find the table. This would introduce a regression, because before WL#7142, a copy of the table was accessible after recovery. FIX#3: Maintain a list of MLOG_FILE_RENAME2 records that have been written to the redo log, but not performed yet in the file system. When performing a checkpoint, re-emit these records to the redo log. In this way, a mismatch between (b) and (c) should be impossible. fil_name_process(): Refactored from fil_name_parse(). Adds an item to the id-to-filename mapping. fil_name_parse(): Parses and applies a MLOG_FILE_NAME, MLOG_FILE_DELETE or MLOG_FILE_RENAME2 record. This implements FIX#1. fil_name_write_rename(): A wrapper function for writing MLOG_FILE_RENAME2 records. fil_op_replay_rename(): Apply MLOG_FILE_RENAME2 records. Replaces fil_op_log_parse_or_replay(), whose logic was moved to fil_name_parse(). fil_tablespace_exists_in_mem(): Return fil_space_t* instead of bool. dict_check_tablespaces_and_store_max_id(): Add the parameter "validate" to implement FIX#2. log_sys->append_on_checkpoint: Extra log records to append in case of a checkpoint. Needed for FIX#3. log_append_on_checkpoint(): New function, to update log_sys->append_on_checkpoint. mtr_write_log(): New function, to append mtr_buf_t to the redo log. fil_names_clear(): Append the data from log_sys->append_on_checkpoint if needed. ha_innobase::commit_inplace_alter_table(): Add any MLOG_FILE_RENAME2 records to log_sys->append_on_checkpoint(), and remove them once the files have been renamed in the file system. mtr_buf_copy_t: A helper functor for copying a mini-transaction log. rb#6282 approved by Jimmy Yang
This directory contains test suites for the MariaDB server. To run currently existing test cases, execute ./mysql-test-run in this directory. Some tests are known to fail on some platforms or be otherwise unreliable. The file "unstable-tests" contains the list of such tests along with a comment for every test. To exclude them from the test run, execute # ./mysql-test-run --skip-test-list=unstable-tests In general you do not have to have to do "make install", and you can have a co-existing MariaDB installation, the tests will not conflict with it. To run the tests in a source directory, you must do "make" first. In Red Hat distributions, you should run the script as user "mysql". The user is created with nologin shell, so the best bet is something like # su - # cd /usr/share/mysql-test # su -s /bin/bash mysql -c "./mysql-test-run --skip-test-list=unstable-tests" This will use the installed MariaDB executables, but will run a private copy of the server process (using data files within /usr/share/mysql-test), so you need not start the mysqld service beforehand. You can omit --skip-test-list option if you want to check whether the listed failures occur for you. To clean up afterwards, remove the created "var" subdirectory, e.g. # su -s /bin/bash - mysql -c "rm -rf /usr/share/mysql-test/var" If one or more tests fail on your system on reasons other than listed in lists of unstable tests, please read the following manual section for instructions on how to report the problem: https://mariadb.com/kb/en/reporting-bugs If you want to use an already running MySQL server for specific tests, use the --extern option to mysql-test-run. Please note that in this mode, you are expected to provide names of the tests to run. For example, here is the command to run the "alias" and "analyze" tests with an external server: # mysql-test-run --extern socket=/tmp/mysql.sock alias analyze To match your setup, you might need to provide other relevant options. With no test names on the command line, mysql-test-run will attempt to execute the default set of tests, which will certainly fail, because many tests cannot run with an external server (they need to control the options with which the server is started, restart the server during execution, etc.) You can create your own test cases. To create a test case, create a new file in the t subdirectory using a text editor. The file should have a .test extension. For example: # xemacs t/test_case_name.test In the file, put a set of SQL statements that create some tables, load test data, and run some queries to manipulate it. Your test should begin by dropping the tables you are going to create and end by dropping them again. This ensures that you can run the test over and over again. If you are using mysqltest commands in your test case, you should create the result file as follows: # mysql-test-run --record test_case_name or # mysqltest --record < t/test_case_name.test If you only have a simple test case consisting of SQL statements and comments, you can create the result file in one of the following ways: # mysql-test-run --record test_case_name # mysql test < t/test_case_name.test > r/test_case_name.result # mysqltest --record --database test --result-file=r/test_case_name.result < t/test_case_name.test When this is done, take a look at r/test_case_name.result . If the result is incorrect, you have found a bug. In this case, you should edit the test result to the correct results so that we can verify that the bug is corrected in future releases. If you want to submit your test case you can send it to maria-developers@lists.launchpad.net or attach it to a bug report on http://mariadb.org/jira/. If the test case is really big or if it contains 'not public' data, then put your .test file and .result file(s) into a tar.gz archive, add a README that explains the problem, ftp the archive to ftp://ftp.askmonty.org/private and submit a report to http://mariadb.org/jira about it. The latest information about mysql-test-run can be found at: https://mariadb.com/kb/en/mariadb/mysqltest/ If you want to create .rdiff files, check https://mariadb.com/kb/en/mariadb/mysql-test-auxiliary-files/