Commit graph

26107 commits

Author SHA1 Message Date
Daniel Black
e80acbbe91 Merge branch 10.6 into 10.7 2022-10-25 16:02:57 +11:00
Nayuta Yanagisawa
c160a115b8 MDEV-27233 Server hangs when using --init-file which loads Spider and creates a Spider table
Spider waits until the server initialization has been completed
(i.e., mysqld_server_started has been set to 1) before creating the
Spider system tables. Spider also wait until the system tables have
been created before instantiating ha_spider.

These waits leads to dead lock when a non-system Spider table is
created by --in-file. This is because queries passed by --in-file
are executed during the server initialization and creating the
non-system Spider table causes an instantiation of ha_spider.

In the first place, there seems to be no need for Spider to do such
a synchronization. Thus, we simply remove the synchronization.
2022-10-24 16:01:32 +09:00
Vlad Lesin
9c04d66d11 MDEV-29622 Wrong assertions in lock_cancel_waiting_and_release() for deadlock resolving caller
Suppose we have two transactions, trx 1 and trx 2.

trx 2 does deadlock resolving from lock_wait(), it sets
victim->lock.was_chosen_as_deadlock_victim=true for trx 1, but has not
yet invoked lock_cancel_waiting_and_release().

trx 1 checks the flag in lock_trx_handle_wait(), and starts rollback
from row_mysql_handle_errors(). It can change trx->lock.wait_thr and
trx->state as it holds trx_t::mutex, but trx 2 has not yet requested it,
as lock_cancel_waiting_and_release() has not yet been called.

After that trx 1 tries to release locks in trx_t::rollback_low(),
invoking trx_t::rollback_finish(). lock_release() is blocked on try to
acquire lock_sys.rd_lock(SRW_LOCK_CALL) in lock_release_try(), as
lock_sys is blocked by trx 2, as deadlock resolution works under
lock_sys.wr_lock(SRW_LOCK_CALL), see Deadlock::report() for details.

trx 2 executes lock_cancel_waiting_and_release() for deadlock victim, i.
e. for trx 1. lock_cancel_waiting_and_release() contains some
trx->lock.wait_thr and trx->state assertions, which will fail, because
trx 1 has changed them during rollback execution.

So, according to the above scenario, it's legal to have
trx->lock.wait_thr==0 and trx->state!=TRX_STATE_ACTIVE in
lock_cancel_waiting_and_release(), if it was invoked from
Deadlock::report(), and the fix is just in the assertion conditions
changing.

The fix is just in changing assertion condition.

There is also lock_wait() cleanup around trx->error_state.

If trx->error_state can be changed not by the owned thread, it must be
protected with lock_sys.wait_mutex, as lock_wait() uses trx->lock.cond
along with that mutex.

Also if trx->error_state was changed before lock_sys.wait_mutex
acquision, then it could be reset with the following code, what is
wrong. Also we need to check trx->error_state before entering waiting
loop, otherwise it can be the case when trx->error_state was set before
lock_sys.wait_mutex acquision, but the thread will be waiting on
trx->lock.cond.
2022-10-21 10:55:19 +03:00
Vlad Lesin
acebe35719 MDEV-29635 race on trx->lock.wait_lock in deadlock resolution
Returning DB_SUCCESS unconditionally if !trx->lock.wait_lock in
lock_trx_handle_wait() is wrong. Because even if
trx->lock.was_chosen_as_deadlock_victim was not set before the first check
in lock_trx_handle_wait(), it can be set after
the check, and trx->lock.wait_lock can be reset by another thread from
lock_reset_lock_and_trx_wait() if the transaction was chosen as deadlock
victim. In this case lock_trx_handle_wait() will return DB_SUCCESS even
the transaction was marked as deadlock victim, and continue execution
instead of rolling back.

The fix is to check trx->lock.was_chosen_as_deadlock_victim once more if
trx->lock.wait_lock is reset, as trx->lock.wait_lock can be reset only
after trx->lock.was_chosen_as_deadlock_victim was set if the transaction
was chosen as deadlock victim.
2022-10-21 10:55:18 +03:00
Marko Mäkelä
ab0190101b MDEV-24402: InnoDB CHECK TABLE ... EXTENDED
Until now, the attribute EXTENDED of CHECK TABLE was ignored by InnoDB,
and InnoDB only counted the records in each index according
to the current read view. Unless the attribute QUICK was specified, the
function btr_validate_index() would be invoked to validate the B-tree
structure (the sibling and child links between index pages).

The EXTENDED check will not only count all index records according to the
current read view, but also ensure that any delete-marked records in the
clustered index are waiting for the purge of history, and that all
secondary index records point to a version of the clustered index record
that is waiting for the purge of history. In other words, no index may
contain orphan records. Normal MVCC reads and the non-EXTENDED version
of CHECK TABLE would ignore these orphans.

Unpurged records merely result in warnings (at most one per index),
not errors, and no indexes will be flagged as corrupted due to such
garbage. It will remain possible to SELECT data from such indexes or
tables (which will skip such records) or to rebuild the table to
reclaim some space.

We introduce purge_sys.end_view that will be (almost) a copy of
purge_sys.view at the end of a batch of purging committed transaction
history. It is not an exact copy, because if the size of a purge batch
is limited by innodb_purge_batch_size, some records that
purge_sys.view would allow to be purged will be left over for
subsequent batches.

The purge_sys.view is relevant in the purge of committed transaction
history, to determine if records are safe to remove. The new
purge_sys.end_view is relevant in MVCC operations and in
CHECK TABLE ... EXTENDED. It tells which undo log records are
safe to access (have not been discarded at the end of a purge batch).

purge_sys.clone_oldest_view<true>(): In trx_lists_init_at_db_start(),
clone the oldest read view similar to purge_sys_t::clone_end_view()
so that CHECK TABLE ... EXTENDED will not report bogus failures between
InnoDB restart and the completed purge of committed transaction history.

purge_sys_t::is_purgeable(): Replaces purge_sys_t::changes_visible()
in the case that purge_sys.latch will not be held by the caller.
Among other things, this guards access to BLOBs. It is not safe to
dereference any BLOBs of a delete-marked purgeable record, because
they may have already been freed.

purge_sys_t::view_guard::view(): Return a reference to purge_sys.view
that will be protected by purge_sys.latch, held by purge_sys_t::view_guard.

purge_sys_t::end_view_guard::view(): Return a reference to
purge_sys.end_view while it is protected by purge_sys.end_latch.
Whenever a thread needs to retrieve an older version of a clustered
index record, it will hold a page latch on the clustered index page
and potentially also on a secondary index page that points to the
clustered index page. If these pages contain purgeable records that
would be accessed by a currently running purge batch, the progress of
the purge batch would be blocked by the page latches. Hence, it is
safe to make a copy of purge_sys.end_view while holding an index page
latch, and consult the copy of the view to determine whether a record
should already have been purged.

btr_validate_index(): Remove a redundant check.

row_check_index_match(): Check if a secondary index record and a
version of a clustered index record match each other.

row_check_index(): Replaces row_scan_index_for_mysql().
Count the records in each index directly, duplicating the relevant
logic from row_search_mvcc(). Initialize check_table_extended_view
for CHECK ... EXTENDED while holding an index leaf page latch.
If we encounter an orphan record, the copy of purge_sys.end_view that
we make is safe for visibility checks, and trx_undo_get_undo_rec() will
check for the safety to access each undo log record. Should that check
fail, we should return DB_MISSING_HISTORY to report a corrupted index.
The EXTENDED check tries to match each secondary index record with
every available clustered index record version, by duplicating the logic
of row_vers_build_for_consistent_read() and invoking
trx_undo_prev_version_build() directly.

Before invoking row_check_index_match() on delete-marked clustered index
record versions, we will consult purge_sys.is_purgeable() in order to
avoid accessing freed BLOBs.

We will always check that the DB_TRX_ID or PAGE_MAX_TRX_ID does not
exceed the global maximum. Orphan secondary index records will be
flagged only if everything up to PAGE_MAX_TRX_ID has been purged.
We warn also about clustered index records whose nonzero DB_TRX_ID
should have been reset in purge or rollback.

trx_set_rw_mode(): Move an assertion from ReadView::set_creator_trx_id().

trx_undo_prev_version_build(): Remove two debug-only parameters,
and return an error code instead of a Boolean.

trx_undo_get_undo_rec(): Return a pointer to the undo log record,
or nullptr if one cannot be retrieved. Instead of consulting the
purge_sys.view, consult the purge_sys.end_view to determine which
records can be accessed.

trx_undo_get_rec_if_purgeable(): A variant of trx_undo_get_undo_rec()
that will consult purge_sys.view instead of purge_sys.end_view.

TRX_UNDO_CHECK_PURGEABILITY: A new parameter to
trx_undo_prev_version_build(), passed by row_vers_old_has_index_entry()
so that purge_sys.view instead of purge_sys.end_view will be consulted
to determine whether a secondary index record may be safely purged.

row_upd_changes_disowned_external(): Remove. This should be more
expensive than briefly latching purge_sys in trx_undo_prev_version_build()
(which may make use of transactional memory).

row_sel_reset_old_vers_heap(): New function, split from
row_sel_build_prev_vers_for_mysql().

row_sel_build_prev_vers_for_mysql(): Reorder some parameters
to simplify the call to row_sel_reset_old_vers_heap().

row_search_for_mysql(): Replaced with direct calls to row_search_mvcc().

sel_node_get_nth_plan(): Define inline in row0sel.h

open_step(): Define at the call site, in simplified form.

sel_node_reset_cursor(): Merged with the only caller open_step().
---
ReadViewBase::check_trx_id_sanity(): Remove.
Let us handle "future" DB_TRX_ID in a more meaningful way:

row_sel_clust_sees(): Return DB_SUCCESS if the record is visible,
DB_SUCCESS_LOCKED_REC if it is invisible, and DB_CORRUPTION if
the DB_TRX_ID is in the future.

row_undo_mod_must_purge(), row_undo_mod_clust(): Silently ignore
corrupted DB_TRX_ID. We are in ROLLBACK, and we should have noticed
that corruption when we were about to modify the record in the first
place (leading us to refuse the operation).

row_vers_build_for_consistent_read(): Return DB_CORRUPTION if
DB_TRX_ID is in the future.

Tested by: Matthias Leich
Reviewed by: Vladislav Lesin
2022-10-21 10:02:54 +03:00
Oleksandr Byelkin
44f2ece543 columnstore-6.4.6-1 2022-10-20 18:55:09 +02:00
Oleksandr Byelkin
ec2b30e736 Merge branch '10.6' into 10.7 2022-10-16 21:40:33 +02:00
Oleksandr Byelkin
822694bd56 Merge branch '10.5' into 10.6 2022-10-15 23:47:33 +02:00
Marko Mäkelä
66e44afd94 Merge 10.4 into 10.5 2022-10-13 17:05:30 +03:00
Marko Mäkelä
f404911557 Merge 10.3 into 10.4 2022-10-13 16:50:26 +03:00
Marko Mäkelä
588efca237 Merge 10.6 into 10.7 2022-10-13 10:05:29 +03:00
Nikita Malyavin
128356b4b1 MDEV-29753 An error is wrongly reported during INSERT with vcol index
See also commits aa8a31da and 64678c for a Bug #22990029 fix.

In this scenario INSERT chose to check if delete unmarking is available for
a just deleted record. To build an update vector, it needed to calculate
the vcols as well. Since this INSERT was not IGNORE-flagged, recalculation
failed.

Solutiuon: temporarily set abort_on_warning=true, while calculating the
column for delete-unmarked insert.
2022-10-12 20:49:45 +03:00
Nikita Malyavin
3cd2c1e8b6 MDEV-29299 SELECT from table with vcol index reports warning
As of now innodb does not store trx_id for each record in secondary index.
The idea behind is following: let us store only per-page max_trx_id, and
delete-mark the records when they are deleted/updated.

If the read starts, it rememders the lowest id of currently active
transaction. Innodb refers to it as trx->read_view->m_up_limit_id.
See also ReadView::open.

When the page is fetched, its max_trx_id is compared to m_up_limit_id.
If the value is lower, and the secondary index record is not delete-marked,
then this page is just safe to read as is. Else, a clustered index could be
needed ato access. See page_get_max_trx_id call in row_search_mvcc, and the
corresponding switch (row_search_idx_cond_check(...)) below.

Virtual columns are required to be updated in case if the record was
delete-marked. The motivation behind it is documented in
Row_sel_get_clust_rec_for_mysql::operator() near
row_sel_sec_rec_is_for_clust_rec call.

This was basically a description why virtual column computation can
normally happen during SELECT, and, generally, a vcol index access.

Sometimes stats tables are updated by innodb. This starts a new
transaction, and it can happen that it didn't finish to the moment of
SELECT execution, forcing virtual columns recomputation. If the result was
a something that normally outputs a warning, like division by zero, then
it could be outputted in a racy manner.

The solution is to suppress the warnings when a column is computed
for the described purpose.
ignore_wrnings argument is added innobase_get_computed_value.
Currently, it is only true for a call from
row_sel_sec_rec_is_for_clust_rec.
2022-10-12 20:49:45 +03:00
Marko Mäkelä
a992c615a6 Merge 10.5 into 10.6 2022-10-12 12:14:13 +03:00
Marko Mäkelä
977c385df3 Merge 10.4 into 10.5 2022-10-12 11:29:32 +03:00
Marko Mäkelä
2f1a4328cb MDEV-29613 fixup: clang -Wunused-but-set-variable 2022-10-11 15:36:24 +03:00
Marko Mäkelä
7434eb566e Merge 10.3 into 10.4 2022-10-11 15:18:49 +03:00
Alexander Barkov
3416315407 A followup for MDEV-29672 Add MTR tests covering key and key segment flags and types
Adding debug output for key and keyseg flags at ha_myisam::open() time.
So now there are three points of debug output:

1. In the very end of mysql_prepare_create_table()
2. In ha_myisam::create(), after the table2myisam() call
3. In ha_myisan::open(), after the mi_open() call

mi_create(), which is is called between 2 and 3, modifies flags for
some data types, so the output in 2 and 3 is different.
2022-10-10 14:10:48 +04:00
Marko Mäkelä
e05ab0cfc5 Silence clang 13 -Wunused-but-set-variable for Bison 2022-10-10 09:36:43 +03:00
Marko Mäkelä
56b97ca03a MDEV-29742 heap number overflow
A previous fix in commit efd8af535a
failed to cover ALTER TABLE.

PageBulk::isSpaceAvailable(): Check for record heap number overflow.
2022-10-10 09:12:55 +03:00
Marko Mäkelä
1d35ec1ae1 Mroonga: GCC 12.2.0 -Og -Wmaybe-uninitialized 2022-10-07 12:49:14 +03:00
Marko Mäkelä
4a8da624b5 Groonga: GCC 12.2.0 -Og -Wuse-after-free
This message would always have been invoked on ptr=NULL.
2022-10-07 12:48:38 +03:00
Marko Mäkelä
9fd91863e6 MDEV-29613 fixup: Mroonga -Wunused-function 2022-10-07 12:46:06 +03:00
Sergei Golubchik
eae037c286 galera crashes in debug builds
after 6b685ea7b0 one can no longer violate the locking protocol
by invoking thd_get_ha_data() on some other thread without
protecting that with a mutex
2022-10-07 11:07:30 +02:00
Marko Mäkelä
1b1501b0f1 Simplify purge a little
row_purge_step(): Process all available purge_node_t::undo_recs.

row_purge_end(): Replaced with purge_node_t::end().

TODO: Do we need a "query graph node" at all for purge?
2022-10-06 13:15:12 +03:00
Marko Mäkelä
ea1415cbb6 MDEV-22718: purge_sys.low_limit_no() is not protected
purge_sys_t::low_limit_no(): Adjust a comment. Actually, this
is protected after all.

TrxUndoRsegsIterator::set_next(): Reduce the critical section
of purge_sys.rseg->latch. Some purge_sys fields are accessed
only by the purge coordinator task.
2022-10-06 13:14:51 +03:00
Marko Mäkelä
97b0eeed2b Cleanup: Add missing const 2022-10-06 13:14:40 +03:00
Marko Mäkelä
959ad2f30f MDEV-29612 ReadViewBase::snapshot() misses an optimization
ReadViewBase::snapshot(): In case m_low_limit_no==m_low_limit_id
and m_ids would include everything between that and m_up_limit_id,
set all fields to m_up_limit_id and clear m_ids, to speed up
changes_visible() and append().

rw_trx_hash_t::debug_iterator(): Add an assertion.
2022-10-06 13:14:16 +03:00
Marko Mäkelä
3e9e377bf6 MDEV-29590 Deadlock between ibuf_insert_to_index_page_low() and DDL
btr_page_reorganize_low(): Do not invoke lock_move_reorganize_page()
on a dummy index during change buffer merge. The ibuf.index page
latch that we are holding may block a DDL operation that is waiting
in ibuf_delete_for_discarded_space() while holding exclusive
lock_sys.latch. ibuf_insert_low() would refuse to buffer a change
if any locks exist for the index page.
2022-10-06 13:14:07 +03:00
Marko Mäkelä
6dc157f8a6 Merge 10.5 into 10.6 2022-10-06 09:22:39 +03:00
Marko Mäkelä
de078e060e Merge 10.4 into 10.5 2022-10-06 08:29:56 +03:00
Marko Mäkelä
65d0c57c1a Merge 10.3 into 10.4 2022-10-05 20:30:57 +03:00
Sergei Golubchik
286acaa796 maintainer mode: build with -Wmissing-braces 2022-10-05 18:22:39 +03:00
Vlad Lesin
c0eda62aec MDEV-27927 row_sel_try_search_shortcut_for_mysql() does not latch a page, violating read view isolation
btr_search_guess_on_hash() would only acquire an index page latch if it
is invoked with ahi_latch=NULL. If it's invoked from
row_sel_try_search_shortcut_for_mysql() with ahi_latch!=NULL, a page
will not be latched, and row_search_mvcc() will get a pointer to the
record, which can be changed by some other transaction before the record
was stored in result buffer with row_sel_store_mysql_rec() call.

ahi_latch argument of btr_cur_search_to_nth_level_func() and
btr_pcur_open_with_no_init_func() is used only for
row_sel_try_search_shortcut_for_mysql().
btr_cur_search_to_nth_level_func(..., ahi_latch !=0, ...) is invoked
only from btr_pcur_open_with_no_init_func(..., ahi_latch !=0, ...),
which, in turns, is invoked only from
row_sel_try_search_shortcut_for_mysql().

I suppose that separate case with ahi_latch!=0 was intentionally
implemented to protect row_sel_store_mysql_rec() call in
row_search_mvcc() just after row_sel_try_search_shortcut_for_mysql()
call. After the ahi_latch was moved from row_seach_mvcc() to
row_sel_try_search_shortcut_for_mysql(), there is no need in it at all
if btr_search_guess_on_hash() latches a page unconditionally. And if
btr_search_guess_on_hash() latched the page, any access to the record in
row_sel_try_search_shortcut_for_mysql() after btr_pcur_open_with_no_init()
call will be protected with the page latch.

The fix is to remove ahi_latch argument from
btr_pcur_open_with_no_init_func(), btr_cur_search_to_nth_level_func()
and btr_search_guess_on_hash().

There will not be test, as to test it we need to freeze some SELECT
execution in the point between row_sel_try_search_shortcut_for_mysql()
and row_sel_store_mysql_rec() calls in row_search_mvcc(), and to change
the record in some other transaction to let row_sel_store_mysql_rec() to
store changed record in result buffer. Buf we can't do this with the
fix, as the page will be latched in btr_search_guess_on_hash() call.
2022-10-05 17:35:21 +03:00
Marko Mäkelä
b0c7b43074 MDEV-29440 fixup: Clean up dict_load_foreigns()
dict_load_foreigns(): Remove the constant parameter uncommitted=false.
The parameter only had to be added to dict_load_foreign().

Spotted by Alexey Midenkov
2022-10-05 11:03:46 +03:00
Marko Mäkelä
df97eb1432 Remove HAVE_SNPRINTF
This fixes up commit 77c184df7c
which explicitly specifies that we use ISO/IEC 9899:1999 (C99),
which includes the snprintf() function.
2022-10-05 10:09:49 +03:00
Marko Mäkelä
1562b2c20b MDEV-29666 InnoDB fails to purge secondary index records when indexed virtual columns exist
row_purge_get_partial(): Replaces trx_undo_rec_get_partial_row().
Also copy the purge_node_t::ref to the purge_node_t::row.
In this way, the clustered index key fields will always be
available, even if thanks to
commit d384ead0f0 (MDEV-14799)
they would no longer be repeated in the remaining part of the
undo log record.
2022-10-05 09:30:33 +03:00
Nayuta Yanagisawa
2154a1fc35 MDEV-29484 Assertion `!trx_free || !trx->locked_connections' failed in spider_free_trx_conn on LOCK TABLES
In MDEV-28352, we've modified spider_free_trx_conn() so that it frees
a connection only when the connection is locking no remote table.

However, when a user connection to a Spider node is disconnected, the
corresponding connections to remote data nodes from the Spider node
must be freed immediately.

Thus, the modification above leads an assertion error on the debug
build and a hang on the non-debug build. We partly revert MDEV-28352
to fix the problem.
2022-10-04 22:09:37 +09:00
Oleksandr Byelkin
b6ebadaa66 Merge branch '10.6' into 10.7 2022-10-04 07:41:35 +02:00
Vlad Lesin
c0817dac99 MDEV-29575 Access to innodb_trx, innodb_locks and innodb_lock_waits along with detached XA's can cause SIGSEGV
trx->mysql_thd can be zeroed-out between thd_get_thread_id() and
thd_query_safe() calls in fill_trx_row(). trx_disconnect_prepared() zeroes out
trx->mysql_thd. And this can cause null pointer dereferencing in
fill_trx_row().

fill_trx_row() is invoked from fetch_data_into_cache() under trx_sys.mutex.

Bug fix is in reseting trx_t::mysql_thd in trx_disconnect_prepared() under
trx_sys.mutex lock too.

MTR test case can't be created for the fix, as we need to wait for
trx_t::mysql_thd reseting in fill_trx_row() after trx_t::mysql_thd was
checked for null while trx_sys.mutex is held. But trx_t::mysql_thd must be
reset in trx_disconnect_prepared() under trx_sys.mutex. There will be deadlock.
2022-10-03 14:41:06 +03:00
Sergei Golubchik
900d7bf360 Merge branch '10.5' into 10.6 2022-10-02 22:14:21 +02:00
Sergei Golubchik
3a2116241b Merge branch '10.4' into 10.5 2022-10-02 14:38:13 +02:00
Sergei Golubchik
d4f6d2f08f Merge branch '10.3' into 10.4 2022-10-01 23:07:26 +02:00
Sergei Golubchik
dd8833bff0 cleanup: suppress rocksdb compilation warning, fix a comment 2022-10-01 17:45:23 +02:00
Sergei Golubchik
194cc36805 Merge branch '10.5' into 10.6 2022-09-30 12:29:24 +02:00
Alexander Barkov
1118e979c2 MDEV-29672 Add MTR tests covering key and key segment flags and types 2022-09-30 11:08:49 +04:00
Anel Husakovic
1f51d6c0f6 MDEV-28548: ER_TABLEACCESS_DENIED_ERROR is missing information about DB
- Added missing information about database of corresponding table for various types of commands
- Update some typos

- Reviewed by: <vicentiu@mariadb.org>
2022-09-30 08:48:57 +02:00
Marko Mäkelä
e29fb95614 Cleanup: Remove innobase_destroy_background_thd()
We do not need a non-inline wrapper for the function
destroy_background_thd().
2022-09-30 08:25:00 +03:00
Sergei Golubchik
6b685ea7b0 correctness assert
thd_get_ha_data() can be used without a lock, but only from the
current thd thread, when calling from anoher thread it *must*
be protected by thd->LOCK_thd_data

* fix group commit code to take thd->LOCK_thd_data
* remove innobase_close_connection() from the innodb background thread,
  it's not needed after 87775402cd and was failing the assert with
  current_thd==0
2022-09-29 10:44:39 +02:00
Sergei Golubchik
de130323b4 MDEV-29368 Assertion `trx->mysql_thd == thd' failed in innobase_kill_query from process_timers/timer_handler and use-after-poison in innobase_kill_query
This is a 10.5 version of 9b750dcbd8, fix for
MDEV-23536 Race condition between KILL and transaction commit

InnoDB needs to remove trx from thd before destroying it (trx), otherwise
a concurrent KILL might get a pointer from thd to a destroyed trx.

ha_close_connection() should allow engines to clear ha_data in
hton->on close_connection(). To prevent the engine from being unloaded
while hton->close_connection() is running, we remove the lock from
ha_data and unlock the plugin manually.
2022-09-29 00:11:02 +02:00