Description:
Recently, when I was reading the source code, I found that there was a logic bug in the func `add_link_advance_tail()` in ut0link_buf.h.
`add_link_advance_tail()` should add a directed link and advance the tail in the buffer if possible. Assume the link to be added is (start_pos, end_pos), if the `tail` of the Link_buf at this time is equal to `start_pos`, then `add_link_advance_tail()` will update the `tail` to `end_pos` directly, and quit.
This could be a bug. If the links are added to Link_buf in the sequence below:
* step1: add_link_advance_tail(0, 1)
* step2: add_link_advance_tail(2, 3)
* step3: add_link_advance_tail(1, 2)
After step 3, the `tail` of this Link_buf will be 2 due to the aforementioned bug. However, the expected value should be 3. If `validate_no_links()` is called after step 3, mysqld will exit due to assertion failure.
Since log_checkpointer and buf_flush_page_coordinator will call `advance_tail()` before performing a checkpoint and flushing dirty pages, this bug has no negative impact for now. But I recommend fixing it to prevent bugs in the future.
How to repeat:
Just read my description, and look at the corresponding code.
The code is at https://github.com/mysql/mysql-server/blob/b79ac1111737174c1b36ab5f63275f0191c000dc/storag...
'''
if (position == from) {
/* can advance m_tail directly and exclusively, and it is unlock */
m_tail.store(to, std::memory_order_release);
} else {
auto index = slot_index(from);
auto &slot = m_links[index];
/* add link */
slot.store(to, std::memory_order_release);
auto stop_condition = [&](Position prev_pos, Position) {
return (prev_pos > from);
};
advance_tail_until(stop_condition);
}
'''
(when `position == from`, update `m_tail` and return directly)