Commit graph

9548 commits

Author SHA1 Message Date
Marko Mäkelä
15ab2e122d MDEV-30132 Crash after recovery, with InnoDB: Tried to read ...
os_file_read(): Merged with os_file_read_no_error_handling().
Crashing on a partial page read is as unhelpful as crashing on a
corrupted page read (commit 0b47c126e3).
Report the file name if it is available via IORequest.
2022-11-30 10:54:03 +02:00
Marko Mäkelä
fc1403d3a9 Cleanup: Remove fil_space_t::is_deferred()
The public data member can be checked directly by the only caller.
2022-11-30 10:41:11 +02:00
Marko Mäkelä
1188ef4ade MDEV-30132 Crash after recovery, with InnoDB: Tried to read ... bytes at offset
fil_space_t::prepare_acquired(): Do not attempt to extend (or shrink)
files that will be processed by recv_sys_t::recover_deferred().
2022-11-30 10:35:40 +02:00
Thirunarayanan Balathandayuthapani
bb29712b45 MDEV-30119 INFORMATION_SCHEMA.INNODB_TABLESPACES_ENCRYPTION.NAME is NULL for undo tablespaces
- Information_schema.innodb_tablespaces_encryption should print
undo tablespace name as innodb_undo001, innodb_undo002 and soon.

- Encryption test should include undo tablespaces count when
the tests are waiting for the condition to check whether all
tables are encrypted or decrypted.
2022-11-29 19:49:53 +05:30
Marko Mäkelä
fdc582fd98 Merge 10.5 into 10.6 2022-11-28 12:20:17 +02:00
Marko Mäkelä
bd694bb7b2 MDEV-24412 InnoDB: Upgrade after a crash is not supported
recv_log_recover_10_4(): Widen the operand of bitwise and to 64 bits,
so that the upgrade check will work when the redo log record is located
more than 4 gigabytes from the start of the first file.
2022-11-28 11:56:09 +02:00
Marko Mäkelä
db14eb16f9 MDEV-30106 InnoDB fails to validate the change buffer on startup
ibuf_init_at_db_start(): Validate the change buffer root page.
A later version may stop creating a change buffer, and this
validation check will prevent a downgrade from such later versions.

ibuf_max_size_update(): If the change buffer was not loaded, do nothing.

dict_boot(): Merge the local variable "error" to "err". Ignore
failures of ibuf_init_at_db_start() if innodb_force_recovery>=4.
2022-11-28 11:34:22 +02:00
Marko Mäkelä
e0d672f30b MDEV-30089 Metrics not incremented for 1st iteration in buf_LRU_free_from_common_LRU_list()
In commit a03dd94be8 as well as
mysql/mysql-server@6ef8c34344
the iterations were changed so that the variable "scanned"
would remain 0 when the first list item qualifies for eviction.

buf_LRU_free_from_unzip_LRU_list(), buf_LRU_free_from_common_LRU_list():
Increment "scanned" when a block can be freed.

buf_LRU_free_from_common_LRU_list(): Remove a redundant condition.
Whenever this function is invoked, buf_pool.LRU should be nonempty,
hence something should always be scanned.

Thanks to Jean-François Gagné for reporting this.
2022-11-28 11:34:00 +02:00
Daniel Black
183ca823bb MDEV-25417: Remove innodb buffer pool load throttling
The very lightest of load would decimate any buffer pool loading
to ~1 page per second. As seen in MDEV-29343 this resulting in
a load taking over an hour on a high end system.

Since MDEV-26547 the fetching is asynchronous, however the loading
has equal access to the IO as the SQL queries.
2022-11-28 11:25:47 +02:00
Marko Mäkelä
05cd10b74c MDEV-29603 fixup: GCC -Wunused-but-set-variable 2022-11-24 16:46:34 +02:00
Marko Mäkelä
604e844944 MDEV-21452 fixup: Remove PFS_NOT_INSTRUMENTED 2022-11-24 15:04:25 +02:00
Marko Mäkelä
6d40274f65 Merge 10.5 into 10.6 2022-11-23 18:13:28 +02:00
Marko Mäkelä
165564d3c3 MDEV-30009 InnoDB shutdown hangs when the change buffer is corrupted
The InnoDB change buffer (ibuf.index, stored in the system tablespace)
and the change buffer bitmaps in persistent tablespaces could get out
of sync with each other: According to the bitmap, no changes exist for
a page, while there actually exist buffered entries in ibuf.index.

InnoDB performs lazy deletion of buffered changes. When a secondary
index leaf page is freed (possibly as part of DROP INDEX), any
buffered changes will not be deleted. Instead, they would be deleted
on a subsequent buf_page_create_low().

One scenario where InnoDB failed to delete buffered changes is
as follows:
1. Some changes were buffered for a secondary index leaf page.
2. The index page had been freed.
3. ibuf_read_merge_pages() invoked ibuf_merge_or_delete_for_page(),
which noticed that the page had been freed, and reset the change buffer
bits, but did not delete the records from ibuf.index.
4. The index page was reallocated for something else.
5. The index page was removed from the buffer pool.
6. Some changes were buffered for the newly created page.
7. Finally, the buffered changes from both 1. and 6. were merged.
8. The index is corrupted.

An alternative outcome is:
4. Shutdown with innodb_fast_shutdown=0 gets into an infinite loop.

An alternative scenario is:
3. ibuf_set_bitmap_for_bulk_load() reset the IBUF_BITMAP_BUFFERED bit
but did not delete the ibuf.index records for that page number.

The shutdown hang was already once fixed in
commit d7a2401750, refactored for
10.5 in commit 77e8a311e1 and
disabled in commit 310dff5d84
due to corruption.

We will fix this as follows:

ibuf_delete_recs(): Delete all ibuf.index entries for the specified page.

ibuf_merge_or_delete_for_page(): When the change buffer bitmap bits
were set and the page had been freed, and the page does not belong
to ibuf.index itself, invoke ibuf_delete_recs(). This prevents the
corruption from occurring when a DML operation is allocating a
previously freed page for which changes had been buffered.

ibuf_set_bitmap_for_bulk_load(): When the change buffer bitmap bits
were set, invoke ibuf_delete_recs(). This prevents the corruption
from occurring when CREATE INDEX is reusing a previously freed page.

ibuf_read_merge_pages(): On slow shutdown, remove the orphan records
by invoking ibuf_delete_recs(). This fixes the hang when the change
buffer had become corrupted. We also remove the dops[] accounting,
because nothing can monitor it during shutdown. We invoke
ibuf_delete_recs() if:
(a) buf_page_get_gen() failed to load the page or merge changes
(b) the page is not a valid index leaf page
(c) the page number is out of tablespace bounds

srv_shutdown(): Invoke ibuf_max_size_update(0) to ensure that
the race condition that motivated us to disable the code in
ibuf_read_merge_pages() in commit 310dff5d84
is no longer possible. That is, during slow shutdown, both the
rollback of transactions and the purge of history will return
early from ibuf_insert_low().

ibuf_merge_space(), ibuf_delete_for_discarded_space(): Cleanup:
Do not allocate a memory heap.

This was implemented by Thirunarayanan Balathandayuthapani
and tested with innodb_change_buffering_debug=1 by Matthias Leich.
2022-11-23 17:34:05 +02:00
Marko Mäkelä
9d388192c7 Cleanup: Say "mariadbd" instead of "mysqld" in InnoDB messages 2022-11-22 15:32:47 +02:00
Marko Mäkelä
cff9939d09 MDEV-30068 Confusing error message when encryption is not available on recovery
fil_name_process(): If fil_ibd_load() returns FIL_LOAD_INVALID,
display the file name and the tablespace identifier.
2022-11-22 15:31:12 +02:00
Marko Mäkelä
46f8c46e94 MDEV-30069 InnoDB: Trying to write ... bytes at ... outside the bounds
recv_sys_t::recover_deferred(): If the *.ibd file already exists,
adjust the size to the tablespace metadata. It could be that
in a multi-batch recovery, we will initially recover an all-zero
*.ibd file to a smaller size, and then a fatal error would be
reported during the last recovery batch.

This bug could be worked around by executing the recovery again.
During the initial (failed) recovery attempt, something should have
been written to the first page of the file and the file size should
be recovered by fil_node_t::read_page0().
2022-11-22 15:00:26 +02:00
Marko Mäkelä
4e5e8166b4 MDEV-19514 fixup: Fix recovery with innodb_change_buffering_debug=1
During crash recovery, recv_sys.apply(true) invokes
mlog_init.mark_ibuf_exist(), which in turn may invoke
recv_sys.apply(true) via the buf_flush_sync() call in
buf_page_get_low(). The simplest fix is to disable the
innodb_change_buffering_debug=1 instrumentation
during crash recovery.
2022-11-21 17:55:35 +02:00
Marko Mäkelä
9aea7d83c8 Merge 10.5 into 10.6 2022-11-17 08:37:35 +02:00
Marko Mäkelä
24fe53477c MDEV-29603 btr_cur_open_at_index_side() is missing some consistency checks
btr_cur_t: Zero-initialize all fields in the default constructor.

btr_cur_t::index: Remove; it duplicated page_cur.index.

Many functions: Remove arguments that were duplicating
page_cur_t::index and page_cur_t::block.

page_cur_open_level(), btr_pcur_open_level(): Replaces
btr_cur_open_at_index_side() for dict_stats_analyze_index().
At the end, release all latches except the dict_index_t::lock
and the buf_page_t::lock on the requested page.

dict_stats_analyze_index(): Rely on mtr_t::rollback_to_savepoint()
to release all uninteresting page latches.

btr_search_guess_on_hash(): Simplify the logic, and invoke
mtr_t::rollback_to_savepoint().

We will use plain C++ std::vector<mtr_memo_slot_t> for mtr_t::m_memo.
In this way, we can avoid setting mtr_memo_slot_t::object to nullptr
and instead just remove garbage from m_memo.

mtr_t::rollback_to_savepoint(): Shrink the vector. We will be needing this
in dict_stats_analyze_index(), where we will release page latches and
only retain the index->lock in mtr_t::m_memo.

mtr_t::release_last_page(): Release the last acquired page latch.
Replaces btr_leaf_page_release().

mtr_t::release(const buf_block_t&): Release a single page latch.
Used in btr_pcur_move_backward_from_page().

mtr_t::memo_release(): Replaced with mtr_t::release().

mtr_t::upgrade_buffer_fix(): Acquire a latch for a buffer-fixed page.
This replaces the double bookkeeping in btr_cur_t::open_leaf().

Reviewed by: Vladislav Lesin
2022-11-17 08:19:01 +02:00
Marko Mäkelä
89ec4b53ac MDEV-29603: Implement btr_cur_t::open_leaf()
btr_cur_t::open_leaf(): Replaces btr_cur_open_at_index_side() for
most calls, except dict_stats_analyze_index(), which is the only
place where we need to open a page at the non-leaf level.
Use btr_block_get() for better error handling.

Also, use the enumeration type btr_latch_mode wherever possible.

Reviewed by: Vladislav Lesin
2022-11-16 09:43:48 +02:00
Marko Mäkelä
6b2d6a81d4 Cleanup: Remove btr_pcur_t::old_stored
The Boolean field btr_pcur_t::old_stored mostly duplicates old_rec.
Let us remove it.
2022-11-16 09:36:36 +02:00
Marko Mäkelä
8442bc6e13 Cleanup: Remove an unnecessary page lookup
btr_cur_search_to_nth_level(): Simply acquire a latch on the already
buffer-fixed page. There is no need to release the buffer-fix and
re-lookup the page.
2022-11-16 09:36:36 +02:00
Marko Mäkelä
a5ed56cd4f Cleanup: Remove BTR_MODIFY_EXTERNAL
btr_blob_log_check_t::check(): Acquire an index U-latch upfront and
pass the flag BTR_MODIFY_LEAF_ALREADY_LATCHED to the search.
2022-11-16 09:36:36 +02:00
Marko Mäkelä
af7bd64edb Cleanup: Use BTR_INSERT_TREE for pessimistic insert 2022-11-16 09:36:36 +02:00
Marko Mäkelä
b363d9758a Cleanup: Use the alias BTR_PURGE_TREE for pessimistic delete 2022-11-16 09:36:36 +02:00
Marko Mäkelä
0b25551a61 MDEV-29999 innodb_undo_log_truncate=ON is not crash safe
If a log checkpoint occurs at the end LSN of mtr.commit_shrink(space)
in trx_purge_truncate_history(), then recovery may fail because
it could try to apply too old log records to too old copies of
undo log pages. This was repeated with the following test:

./mtr innodb.undo_log_truncate,4k,strict_full_crc32

recv_sys_t::trim(): Move some code to the caller.

recv_sys_t::apply(): For undo tablespace truncation, discard
all old redo log for the undo tablespace, and then truncate
the file to the desired size.

Tested by: Matthias Leich
2022-11-15 16:56:13 +02:00
Marko Mäkelä
ae6ebafd81 Merge 10.5 into 10.6 2022-11-14 15:44:55 +02:00
Marko Mäkelä
dc2741be52 MDEV-29984 innodb_fast_shutdown=0 fails to report change buffer merge progress
ibuf.size, ibuf.max_size: Changed the type to Atomic_relaxed<ulint>
in order to fix some (not all) race conditions.

ibuf_contract(): Renamed from ibuf_merge_pages(ulint*).

ibuf_merge(), ibuf_merge_all(): Removed.

srv_shutdown(): Invoke log_free_check() and ibuf_contract(). Even though
ibuf_contract() is not writing anything, it will trigger calls of
ibuf_merge_or_delete_for_page(), which will write something. Because
we cannot invoke log_free_check() at that low level, we must invoke
it at the high level.

srv_shutdown_print(): Replaces srv_shutdown_print_master_pending().
Report progress and remaining work every 15 seconds. For the
change buffer merge, the remaining work is indicated by ibuf.size.
2022-11-14 15:40:28 +02:00
Marko Mäkelä
744b33c287 Cleanup: Remove a useless header file 2022-11-14 14:12:20 +02:00
Marko Mäkelä
ee7fba1749 MDEV-16264 fixup: Remove unused variables 2022-11-14 14:01:37 +02:00
Marko Mäkelä
c82f3f1b04 MDEV-29978 Corruption errors upon CHECK on temporary InnoDB table
row_check_index(): Treat secondary indexes of temporary tables as if
SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED
is in effect. That is, only consider the delete-mark and nothing else.
2022-11-14 13:08:00 +02:00
Marko Mäkelä
e0e096faaa MDEV-29982 Improve the InnoDB log overwrite error message
The InnoDB write-ahead log ib_logfile0 is of fixed size,
specified by innodb_log_file_size. If the tail of the log
manages to overwrite the head (latest checkpoint) of the log,
crash recovery will be broken.

Let us clarify the messages about this, including adding
a message on the completion of a log checkpoint that notes
that the dangerous situation is over.

To reproduce the dangerous scenario, we will introduce the
debug injection label ib_log_checkpoint_avoid_hard, which will
avoid log checkpoints even harder than the previous
ib_log_checkpoint_avoid.

log_t::overwrite_warned: The first known dangerous log sequence number.
Set in log_close() and cleared in log_write_checkpoint_info(),
which will output a "Crash recovery was broken" message.
2022-11-14 12:18:03 +02:00
Marko Mäkelä
2283f82de5 MDEV-29905 fixup: Remove some unnecessary code
srv_shutdown(): Do not call log_free_check(), because it will now
be repeatedly called by ibuf_merge_all(). Do not call
srv_sync_log_buffer_in_background(), because we do not actually care
about durability during shutdown. Log writes will already be triggered
by buf_flush_page_cleaner() for writing back modified pages, possibly by
log_free_check().

logs_empty_and_mark_files_at_shutdown(): Clean up a condition.
This function is the caller of srv_shutdown(), and it will ensure that
the log and the buffer pool will be in clean state before shutdown.
2022-11-14 10:22:29 +02:00
Marko Mäkelä
67f4ba240e MDEV-29996 Duplicated call to buf_page_t::set_ibuf_exist() on recovery
mlog_init_t::mark_ibuf_exist(): After applying the changes,
invoke clear().

It turns out that multiple calls to recv_sys.apply(true) are
possible during recovery. Therefore, we might redundantly
invoke mlog_init_t::mark_ibuf_exist() multiple times.

Starting with commit aaef2e1d8c
the call buf_page_t::set_ibuf_exist() is not idempotent,
because the flag is actually represented by 2 values of a
3-bit state field.
2022-11-10 17:30:55 +02:00
Marko Mäkelä
da21f3f428 Merge 10.5 into 10.6 2022-11-10 17:30:15 +02:00
Marko Mäkelä
7ee612c912 MDEV-21174 fixup: Remove mtr_t::release_page()
mtr_t::release_page(): Remove. The function became unused in
commit 56f6dab1d0
when the call was replaced with a call to mtr_t::memo_release().
2022-11-10 12:50:44 +02:00
Marko Mäkelä
a75ec07b42 MDEV-27234 fixup: Remove a bogus assertion
Starting with commit 8f8ba75855
the assertion would fail in
./mtr --mysqld=--innodb-adaptive-hash-index innodb.instant_alter_crash
and it would keep failing even after
commit d2e649aec2
2022-11-09 16:45:36 +02:00
Marko Mäkelä
3278c57917 Merge 10.4 into 10.5 2022-11-09 09:30:37 +02:00
Marko Mäkelä
20969aa412 Merge 10.3 into 10.4 2022-11-09 09:28:39 +02:00
Marko Mäkelä
6b91792a08 MDEV-29883 Deadlock between InnoDB statistics update and BLOB insert
This is a backport of commit 8b6a308e46
from MariaDB Server 10.6.11. No attempt to reproduce the hang
in earlier an earlier version of MariaDB Server than 10.6 was made.

In each caller of fseg_n_reserved_pages() except ibuf_init_at_db_start()
which is a special case for ibuf.index at database startup, we must hold
an index latch that prevents concurrent allocation or freeing of index
pages.

Any operation that allocates or free pages that belong to an index tree
must first acquire an index latch in non-shared mode, and while
holding that, acquire an index root page latch in non-shared mode.

btr_get_size(), btr_get_size_and_reserved(): Assert that a strong enough
index latch is being held.

dict_stats_update_transient_for_index(),
dict_stats_analyze_index(): Acquire a strong enough index latch.

These operations had followed the same order of acquiring latches in
every InnoDB version since the very beginning
(commit c533308a15).

The hang was introduced in
commit 2e814d4702 which imported
mysql/mysql-server@ac74632293
which failed to strengthen the locking requirements of the function
btr_get_size().
2022-11-09 09:23:18 +02:00
Marko Mäkelä
2ac1edb1c3 Merge 10.5 into 10.6 2022-11-08 17:37:22 +02:00
Marko Mäkelä
e572c745dc MDEV-29504/MDEV-29849 TRUNCATE breaks FOREIGN KEY locking
ha_innobase::referenced_by_foreign_key(): Protect the check with
dict_sys.freeze(), to prevent races with TRUNCATE TABLE.
The test innodb.instant_alter_crash has been adjusted for this
additional locking.

dict_table_is_referenced_by_foreign_key(): Removed (merged to
the only caller).

create_table_info_t::create_table(): Ignore missing indexes for
FOREIGN KEY constraints if foreign_key_checks=0.

create_table_info_t::create_table_update_dict(): Rewritten as
a static function. Do not return any error.

ha_innobase::create(): When trx!=nullptr and we are operating
on a persistent table, do not rollback, commit, or release the
data dictionary latch.

ha_innobase::truncate(): Protect the entire critical section
with an exclusive dict_sys.latch, so that
ha_innobase::referenced_by_foreign_key() on referenced tables
will return a consistent result. In case of a failure,
invoke dict_load_foreigns() to restore also any FOREIGN KEY
constraints.

ha_innobase::free_foreign_key_create_info(): Define inline.

lock_release(): Disregard innodb_evict_tables_on_commit_debug=ON
when dict_sys.locked() holds. It would hold when fts_load_stopword()
is invoked by create_table_info_t::create_table_update_dict().

dict_sys_t::locked(): Return whether the current thread is holding
the exclusive dict_sys.latch.

dict_sys_t::frozen_not_locked(): Return whether any thread is
holding a shared dict_sys.latch.

In the test main.mysql_upgrade, the InnoDB persistent statistics
will no longer be recalculated in ha_innobase::open() as part of
CHECK TABLE ... FOR UPGRADE. They were deleted earlier in the test.

Tested by: Matthias Leich
2022-11-08 17:34:34 +02:00
Marko Mäkelä
a732d5e2ba Merge 10.4 into 10.5 2022-11-08 17:01:28 +02:00
Marko Mäkelä
8fb176c3c1 MDEV-27121 fixup: mariabackup.mdev-14447,full_crc32 2022-11-08 16:59:36 +02:00
Marko Mäkelä
93b4f84ab2 Merge 10.3 into 10.4 2022-11-08 16:04:01 +02:00
Marko Mäkelä
2ef2e2322a MDEV-29856 heap-use-after-poison in row_merge_spatial_rows() w/ column prefix
spatial_index_info: Replaces index_tuple_info_t. Always take
a memory heap as a parameter to the member functions.
Remove pointer indirection for m_dtuple_vec.

spatial_index_info::add(): Duplicate any PRIMARY KEY fields that would
point to within ext->buf because that buffer will be allocated in
a shorter-lifetime memory heap.
2022-11-08 15:26:34 +02:00
Thirunarayanan Balathandayuthapani
f4519fb772 MDEV-28797 Assertion `page_rec_is_user_rec(rec)' failed in PageBulk::getSplitRec
- During alter operation of compressed table, page split operation
chooses the first record of the page as split record and it leads
to empty left page. This issue caused by the commit 77b3959b5c (MDEV-28457).

page_rec_is_second(), page_rec_is_second_last(): Removed the functions
since it is a deadcode.
2022-11-08 15:27:29 +05:30
Thirunarayanan Balathandayuthapani
db85d8b093 MDEV-29853 Assertion `!strstr(table->name.m_name, "/FTS_") || purge_sys.must_wait_FTS()' failed in trx_t::commit
- Failing debug assertion is to indicate whether the purge thread
is waiting when fts auxilary table is being dropped. But assertion
fails if the table name contains FTS_. So in fts_drop_table(), InnoDB
sets the auxilary table flag in transaction modified table list.
2022-11-08 15:27:29 +05:30
Thirunarayanan Balathandayuthapani
689e951227 MDEV-29518 ASAN Failure on i_s query when tablespace does rename operation
- InnoDB information schema query access the tablespace name after
getting freed by concurrent rename operation. To avoid this, InnoDB
should take exclusive tablespace latch during rename operation
and I_S query should take shared tablespace latch before accessing
the name
2022-11-08 15:27:29 +05:30
Marko Mäkelä
b737d09dbc MDEV-29905 Change buffer operations fail to check for log file overflow
Every operation that is going to write redo log is supposed to
invoke log_free_check() before acquiring any latches. If there
is a risk of log buffer overrun, a log checkpoint would be
triggered by that call.

ibuf_merge_space(), ibuf_merge_in_background(),
ibuf_delete_for_discarded_space(): Invoke log_free_check()
when the current thread is not holding any page latches.

Unfortunately, in lower-level code called from ibuf_insert()
or ibuf_merge_or_delete_for_page(), some page latches may be
held and a call to log_free_check() could hang.

ibuf_set_bitmap_for_bulk_load(): Use the caller's mini-transaction.
The caller should have invoked log_free_check() while not holding
any page latches.
2022-11-08 11:37:43 +02:00