Why do we need full buffer pool flush during crash recovery? #91
Replies: 6 comments 27 replies
|
I am afraid the historical reason for that might be lost - to me it looks like some accidental remnant from much older design, probably dating back to: in which this fragment seemed to be moved from a place which had this code comment: I can't really speak on behalf of the author, and there's not much details about the reasoning, behind it. At any rate the current code looks way different than it looked back then. I think I can speak more about the current situation in 26.7.0, which is that we not only write it back to disc, but also evict the pages from buffer pool.
At any rate: if you have a real world data about the
And to answer you question directly: I am not aware of any good reason to force write back of dirty pages to disc, or to make a checkpoint, before opening for public, per se. AFAICT the InnoDB should work just fine if we start in a dirtied state (although care would have to be taken to properly sort the flush lists etc.). It seems that it is just a side effect of some other things we want to achieve (in the latest version of the code: avoiding issues with ibuf). As for the original reason for doing these flushes in ~2014, I can only guess these were done to mask some other trickery - older codebase used to modify some pages or files directly, without redo-logging, and to hide this dirty secret it had to write pages back to disc. Was that the reason in this particular case IDK. |
|
Thanks for the detailed reply. That clarified quite a few things. Though now I have a new set of questions/observations :)
|
|
Ad 1. Yes, if we look just at theoretical performance impact, then write-back + eviction in 26.7.0 is strictly worse than write-back 9.7 alone, but also not that much worse: the additional cost comes mostly from having to re-read the same pages again once they are accessed next time. But what we care more is correctness and empirical performance impact. We are also aware that the current implementation is not necessarily on the pareto-optimal frontier of all the trade-offs here, mostly because we have also traded against complexity. So, if we will see this to cause significant slowdown in real world scenarios, we might revisit this part, and try to evict more surgically Ad 2. Some time ago InnoDB gained "Persistent Table Metadata" (PTM) which is used (infrequently) for marking indexes as corrupt, and (very frequently) for storing autoincrement value. The architecture of PTM in 9.7 is such, that it queues high-level operations (basically "UPSERT INTO ptm SET val=6 WHERE table_id=7") into the redo log which otherwise talks in very low-level language of changes to individual pages. To redo such ptm operation one has to have first reconstructed a fully operational ptm table, i.e. apply all the physical changes to its pages first, and only then try to perform all the collected UPSERTS logically. This means 9.7 can not really start checkpointing/reclaiming/deleting of old redo logs, until it finishes reading them all. In 26.7.0 we WL#15550 "InnoDB: Decouple Persistent Table Metadata from checkpointing" will get rid of the write-path of this mechanism, but still has to support the read part for seamless upgrade. Perhaps in 27.x we will be able to enable checkpointing during recovery. Note that InnoDB in 9.7 is not applying ibuf changes for first N-1 batches of redo log recovery, instead doing write-back + eviction, then in the last batch it applies ibuf changes, and doesn't evict, but (as you've found) does a write-back anyway. This behaviour in 9.7 is almost correct, except for the risk of running out of redo log space, which we fix in 26.7.0 Ad 3. Yes, I am afraid you a right that this case might be frequent. Once you have a real world scenario, we will be interested in comparison of three things: (A) the way 9.7 does it, which is only write-back, (B) the way 26.7.0 does it, which is write-back + eviction, (C) a hypothetical optimal way of doing it, which is to limit write-back and eviction only to the pages which have have ibuf changes buffered for them Ad 4. Thanks. Yes, the thing is it is not straightforward to implement - and we wanted to start with something correct first. There are some chicken and egg problems like to know if a page has any changes buffered you need to first recover the page which stores this information etc. This isn't rocket science, but it isn't trivial neither. We've opted for safe approach in first release. There's still room for simple-yet-useful heuristics like "just check if ibuf is empty" which probably solve most of cases. We might explore this. The chance of us exploring it, depends on seeing real world data showing it to be the problem |
|
Hi Inaam! Ad a) The PTM up to 9.7 including, is implemented in a rather complicated way, which consists of
The idea was roughly that we update the in-memory counters, and emit MLOG_TABLE_METADATA record as a memo to also do it to the mysql.innodb_dynamic_metadata table later in case we forget. From time to time (for example before doing a checkpoint) MySQL writes the state from memory to the mysql.innodb_dynamic_metadata, after which it considers that all the MLOG_TABLE_METADATA redo logs emitted "before" are no longer needed. What will change in 26.x is that we will no longer emit MLOG_TABLE_METADATA records, because they were difficult to handle during recovery. In future versions (say 28.x) we might get rid of this part, too. Ad b) Yes, skipping application of ibuf changes during first N-1 batches was there since early days. I am not sure which of my sentences made you think I consider it a new behaviour. Note that any new behaviour I describe will come in 26.x, not in 9.7. The new thing will be that even in the Nth batch 26.x will not apply ibuf changes. 9.7 was applying them, which can cause a deadlock. The 26.x prefers to not deadlock during recovery, at the expense of evicting the pages. Ad c) great, thank you Ad d) good ideas, thank you |
|
I am going to talk about this in contributor summit. I was told to upload the slides here. |
|
The following is a PoC of what I have in mind. It's based on 26.x but I think it is easy to backport. There are ways to improve upon it, for sure:
Anyway, I'd appreciate testing this patch/idea on real world data |
Uh oh!
There was an error while loading. Please reload this page.
I want to understand the reason behind why we do full buffer pool flush (synchronously) during crash recovery (https://github.com/mysql/mysql-server/blob/845d525d49c8027a4d0cdcc43372c96ba295c857/storage/innobase/srv/srv0start.cc#L1809). There are few things to note here:
The way InnoDB works, if our last checkpoint is at LSN X and then we crash at LSN Y, then during recovery once we have applied the redo records all the way upto LSN Y, we should be able to open the database for business with still LSN X as our last checkpoint LSN. True, we can have some corner cases like resizing the log files and stuff but typically i.e.: in 99.99% of the cases we should be able to avoid this full flushing penalty.
All reactions