[MDEV-30671] innodb_undo_log_truncate=ON fails to wait for purge of transaction history Created: 2023-02-17 Updated: 2023-09-12 Resolved: 2023-02-27 |
|
| Status: | Closed |
| Project: | MariaDB Server |
| Component/s: | Storage Engine - InnoDB |
| Affects Version/s: | 10.2, 10.3, 10.4, 10.5, 10.6, 10.7, 10.8, 10.9, 10.10, 10.11, 11.0 |
| Fix Version/s: | 10.11.3, 11.0.2, 10.5.20, 10.6.13, 10.7.8, 10.8.8, 10.9.6, 10.10.4 |
| Type: | Bug | Priority: | Critical |
| Reporter: | Marko Mäkelä | Assignee: | Marko Mäkelä |
| Resolution: | Fixed | Votes: | 1 |
| Labels: | rr-profile-analyzed | ||
| Issue Links: |
|
||||||||||||||||||||||||||||||||||||||||||||
| Description |
|
mleich produced an rr replay trace of an execution where InnoDB crashes soon after being started up on a freshly initialized database, without involving any crash recovery, soon after an undo tablespace was truncated:
After extensive debugging, I concluded that the problem is that undo tablespace truncation only waits until there are no active transactions (which could be potentially rolled back) in any rollback segment that is stored in the undo tablespace that is being considered for truncation. There is a check like this in trx_purge_truncate_history():
At this point of time, rseg->needs_purge, which was added in At the time of the crash, the DB_TRX_ID=0x2aea of the clustered index record whose history we are attempting to fetch, is explicitly listed in the purge_sys.view, meaning that its history must not be purged yet:
I think that the following could fix the bug:
|
| Comments |
| Comment by Marko Mäkelä [ 2023-02-17 ] | |||||||||||||||||||||||||||
|
It turns out that rseg->needs_purge will not be reset when everything belonging to a rollback segment has been purged:
Without this, the test innodb.undo_truncate_recover would fail, and I suppose the undo truncation would never be triggered, unless the server was restarted in between. | |||||||||||||||||||||||||||
| Comment by Matthias Leich [ 2023-02-20 ] | |||||||||||||||||||||||||||
|
origin/bb-10.5- | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-20 ] | |||||||||||||||||||||||||||
|
Unfortunately, the test innodb.dml_purge started to fail with this change, indicating that some history was not purged. I tried adding an explicit wait for a purge after the rollback that the test initiated. Even if I changed the test to perform a slow shutdown before examining the contents of the data file, it would occasionally fail. In other words, the fix will need to be revised and retested. First, I need to generate rr replay traces leading to a failure. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-21 ] | |||||||||||||||||||||||||||
|
I can produce rr replay traces of failures with the current fix and the following:
The trick is to force more frequent context switches by starting many more concurrent client/server process pairs than there are CPU cores on the system. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-21 ] | |||||||||||||||||||||||||||
|
The following is the relevant part of the test:
In the trace that I am debugging, at the time the connection default completed the ALTER TABLE and the UPDATE, trx_sys.rseg_history_length was incremented to 15 and 16. Then, the purge coordinator task would decrement trx_sys.rseg_history_length one by one all the way to 3, without buffer-fixing the clustered index root page at all. The first buffer-fix will be for the UPDATE t1 SET b=4 WHERE a=3. This is still fine: we have 3 committed single-statement transactions (INSERT, ALTER, UPDATE) whose history cannot be purged, because the connection prevent_purge is hogging an older read view. After disconnect prevent_purge, all of the old history may be purged, but for some reason the history was only purged for the last record: In fact, no purge activity took place on the page before the UPDATE of con1 accesses the last record, carrying DB_TRX_ID=0x23 at that time. It will update the record to During the entire execution, the only call to trx_undo_rec_copy() is by the rollback. After the ALTER TABLE was completed and the trx_sys.rseg_history_len reached 3, there is this call, but it looks like the undo records have been copied off the undo page(s) already:
I will have to debug this deeper before I can come up with a sufficient wait condition. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-21 ] | |||||||||||||||||||||||||||
|
I can reproduce this even with innodb_purge_threads=1, that is, only the purge_coordinator_callback() would take care of purging history, not delegating any work to purge_worker_callback() threads. This will ease debugging a lot. The update of purge_sys.view gives the permission to remove some more history:
Later, the trx_sys.rseg_history_len is being decremented in the same thread:
I must find out why there was no attempt to access to the index page in between. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-21 ] | |||||||||||||||||||||||||||
|
With the following patch (reverting a hunk from the original attempted fix), the test innodb.dml_purge would no longer fail, but the test innodb.undo_truncate_recover would fail to trigger a truncation of the undo log:
I must come up with better logic for determining when all undo log for a rollback segment has been processed. A undo log page may contain records that belong to multiple transactions. This undo page was also being used for the committed UPDATE statement, and its history was definitely not purged yet. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-22 ] | |||||||||||||||||||||||||||
|
I think that we must replace the Boolean flag trx_rseg_t::needs_purge with a trx_id_t of the last transaction in the rollback segment that needs purging. This field must also be reliably recovered from the undo header pages on InnoDB startup. The field TRX_UNDO_NEEDS_PURGE a.k.a. TRX_UNDO_DEL_MARKS would become redundant. To avoid changing the file format, we will only remove some reads of that field, not any writes. Tomorrow, I hope to fix a small number of hanging tests. Special handling will be needed to avoid a shutdown hang with innodb_fast_shutdown=0 if any transactions in XA PREPARE state exist. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-23 ] | |||||||||||||||||||||||||||
|
The tests innodb.xa_recovery innodb.recovery_shutdown would hang on shutdown in the 10.5 based development branch, but not 10.6. I will try to find the reason tomorrow. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-24 ] | |||||||||||||||||||||||||||
|
The fix of the hangs turned out to be this simple:
When the function trx_purge_truncate_rseg_history() finds that the entire rollback segment is empty, it will call trx_purge_free_segment(). In that function, a debug assertion checks that !rseg->needs_purge, that is, no records that should have been purged would be lost. In case the rollback segment contains any active transactions or transactions in the XA PREPARE transactions, then trx_purge_free_segment() will not be called, but instead trx_purge_remove_log_hdr() will be called in order to remove individual log headers that belong to committed transactions. The shutdown in the tests would hang only in case the XA PREPARE transactions happened to be stored in the same rollback segment where some history remains to be purged. That was never the case when I ran the tests with ./mtr --rr and therefore the hang could not be reproduced. | |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-24 ] | |||||||||||||||||||||||||||
|
Actually, the conditions on rseg are better "pushed down" to trx_purge_truncate_rseg_history(), so that we will only invoke trx_purge_truncate_rseg_history() when the rollback segment is empty of history and nothing will be added to it by currently active transactions. | |||||||||||||||||||||||||||
| Comment by Matthias Leich [ 2023-02-24 ] | |||||||||||||||||||||||||||
|
| |||||||||||||||||||||||||||
| Comment by Marko Mäkelä [ 2023-02-27 ] | |||||||||||||||||||||||||||
|
I have pushed this to 10.5 and merged to 10.6. I do not expect major conflicts for later releases. | |||||||||||||||||||||||||||
| Comment by Larry Adams [ 2023-06-20 ] | |||||||||||||||||||||||||||
|
Marko, can you confirm this made it to ES 10.6.14-9? |