The special flag REC_INFO_MIN_REC_FLAG used to be only set on the
first record in the leftmost node pointer page of each level of the tree.
It was never set on leaf pages.
MDEV-11369 Instant ADD COLUMN in MariaDB Server 10.3 repurposed the flag
to identify a hidden metadata record, which is stored in the first record
on the leftmost leaf page.
If the adaptive hash index points to records in the leftmost leaf page
after instant ALTER TABLE, we would have such a metadata record in the
table, an assertion could fail when trying to validate the index record.
In a release build, we might wrongly qualify the hidden metadata record
and thus return garbage results.
cmp_dtuple_rec_with_match_bytes(): If the REC_INFO_MIN_REC_FLAG is
set on the record, assert that this is the first record on the
leftmost page and that the record is a metadata record, and finally
return 1, because by definition, anything is greater than the
minimum record.
Also, related to MDEV-15522, MDEV-17304, MDEV-17835,
remove the Galera xtrabackup tests, because xtrabackup never worked
with MariaDB Server 10.3 due to InnoDB redo log format changes.
dict_create_add_foreigns_to_dictionary(): Do not commit the transaction.
The operation can still fail in dict_load_foreigns(), and we want
to be able to roll back the transaction.
create_table_info_t::create_table(): Never reset m_drop_before_rollback,
and never commit the transaction. We use a single point of rollback
in ha_innobase::create(). Merge the logic from
row_table_add_foreign_constraints().
This is a regression due to MDEV-17816.
When creating a table fails, we must roll back the dictionary
transaction. Because the rollback may rename tables, and because
InnoDB lacks proper undo logging for CREATE operations, we must
drop the incompletely created table before rolling back the
transaction, which could include a RENAME operation.
But, we must not blindly drop the table by name; after all,
the operation could have failed because another table by the
same name already existed.
create_table_info_t::m_drop_before_rollback: A flag that is set
if the table needs to be dropped before transaction rollback.
create_table_info_t::create_table(): Remove some duplicated
error handling.
ha_innobase::create(): On error, only drop the table if it was
actually created.
fil_space_t::add(): Replaces fil_node_create(), fil_node_create_low().
Let the caller pass fil_node_t::handle, to avoid having to close and
re-open files.
fil_node_t::read_page0(): Refactored from fil_node_open_file().
Read the first page of a data file.
fil_node_open_file(): Open the file only once.
srv_undo_tablespace_open(): Set the file handle for the opened
undo tablespace. This should ensure that ut_ad(file->is_open())
no longer fails in recv_add_trim().
xtrabackup_backup_func(): Remove some dead code.
xb_fil_cur_open(): Open files only if needed. Undo tablespaces
should already have been opened.
When dropping a partially created table due to failure,
use SQLCOM_TRUNCATE instead of SQLCOM_DROP_DB, so that
no foreign key constraints will be touched. If any
constraints were added as part of the creation, they would
be reverted as part of the transaction rollback.
We need an explicit call to row_drop_table_for_mysql(),
because InnoDB does not do proper undo logging for CREATE TABLE,
but would only drop the table at the end of the rollback.
This would not work if the transaction combines both
RENAME and CREATE, like TRUNCATE now does.
dict_table_t::prepare_instant(): Remove too strict assertions that
could fail if the MariaDB and InnoDB data dictionaries are out of sync.
That the dictionaries got out of sync during TRUNCATE TABLE
is a separate bug was fixed in 10.2 by
commit 971e1d8677.
The error handling in the MDEV-13564 TRUNCATE TABLE was broken
when an error occurred during table creation.
row_create_index_for_mysql(): Do not drop the table on error.
fts_create_one_common_table(), fts_create_one_index_table():
Do drop the table on error.
create_index(), create_table_info_t::create_table():
Let the caller handle the index creation errors.
ha_innobase::create(): If create_table_info_t::create_table()
fails, drop the incomplete table, roll back the transaction,
and finally return an error to the caller.
lock_rec_queue_validate(): Assert page_rec_is_leaf(rec), except when
the record is a page infimum or supremum.
lock_rec_validate_page(): Relax the assertion that failed.
The assertion was reachable when the record lock bitmap was empty.
lock_rec_insert_check_and_lock(): Assert page_is_leaf().
Several race conditions between MDEV-15562 instant ALTER TABLE and purge
were observed.
The most obvious race condition resulted in a reported assertion failure in
dict_index_t::instant_add_field(): instant.n_core_fields == n_core_fields
would not hold if the table was emptied by purge after the time
dict_table_t::prepare_instant() was called.
During purge, it can turn out that the table is logically empty, only
containing a metadata record. If the metadata record is of the type
created by MDEV-11369 instant ADD COLUMN, it can be removed and
dict_index_t::clear_instant_add() can be called. This will convert the
table to the canonical non-instant format. (If the metadata record is
of the MDEV-15562 type, then it can only be deleted if the table becomes
empty as the result of rollback of an instant ALTER TABLE operation.)
row_purge_remove_clust_if_poss_low(): Add a debug check that ensures
that purge can never remove a MDEV-15562 metadata record.
ha_innobase::open(): Add a comment about the necessity of rolling
back any recovered instant ALTER TABLE transaction on the table.
instant_metadata_lock(): An auxiliary function to acquire a page latch
on the metadata record, to prevent race conditions.
dict_table_t::prepare_instant(), dict_index_t::instant_add_field(),
dict_table_t::rollback_instant(), innobase_instant_try():
Invoke instant_metadata_lock() in order to prevent race conditions.
dict_index_t::instant_add_field(): Correct debug assertions.
The == was guaranteed by code in dict_table_t::prepare_instant()
that was introduced in MDEV-15562. Due to the race condition,
we could occasionally have <=, but never >= like the code was
after MDEV-11369.
ha_innobase_inplace_ctx::instant_column(): Wrapper for
dict_table_t::instant_column(). Add debug assertions.
InnoDB in MySQL 5.7 introduced two new parameters to the function
dict_hdr_get_new_id(), to allow redo logging to be disabled when
assigning identifiers to temporary tables or during the
backup-unfriendly TRUNCATE TABLE that was replaced in MariaDB
by MDEV-13564.
Now that MariaDB 10.4.0 removed the crash recovery code for the
backup-unfriendly TRUNCATE, we can revert dict_hdr_get_new_id()
to be used only for persistent data structures.
dict_table_assign_new_id(): Remove. This was a simple 2-line function
that was called from few places.
dict_table_open_on_id_low(): Declare in the only file where it
is called.
dict_sys_t::temp_id_hash: A separate lookup table for temporary tables.
Table names will be in the common dict_sys_t::table_hash.
dict_sys_t::get_temporary_table_id(): Assign a temporary table ID.
dict_sys_t::get_table(): Look up a persistent table.
dict_sys_t::get_temporary_table(): Look up a temporary table.
dict_sys_t::temp_table_id: The sequence of temporary table identifiers.
Starts from DICT_HDR_FIRST_ID, so that we can continue to simply compare
dict_table_t::id to a few constants for the persistent hard-coded
data dictionary tables.
undo_node_t::state: Distinguish temporary and persistent tables.
lock_check_dict_lock(), lock_get_table_id(): Assert that there cannot
be locks on temporary tables.
row_rec_to_index_entry_impl(): Assert that there cannot be metadata
records on temporary tables.
row_undo_ins_parse_undo_rec(): Distinguish temporary and persistent tables.
Move some assertions from the only caller. Return whether the table was
found.
row_undo_ins(): Add some assertions.
row_undo_mod_clust(), row_undo_mod(): Do not assign node->state.
Let row_undo() do that.
row_undo_mod_parse_undo_rec(): Distinguish temporary and persistent tables.
Move some assertions from the only caller. Return whether the table was
found.
row_undo_try_truncate(): Renamed and simplified from trx_roll_try_truncate().
row_undo_rec_get(): Replaces trx_roll_pop_top_rec_of_trx() and
trx_roll_pop_top_rec(). Fetch an undo log record, and assign undo->state
accordingly.
trx_undo_truncate_end(): Acquire the rseg->mutex only for the minimum
required duration, and release it between mini-transactions.
There was a race condition between ALTER TABLE and purge.
If a table turns out to be logically empty when instant ALTER TABLE
is executing, we will convert the table to the canonical format,
to avoid overhead during subsequent accesses, and to allow the
data file to be imported into older versions of MariaDB.
It could happen that at the time the table is logically empty,
there still exists an undo log record for updating the hidden
metadata record for an earlier instant ALTER TABLE operation.
If the table was converted to the canonical format before
purge processes this undo log record, the undo log record
could be referring to index fields that no longer exist,
causing a crash.
To prevent the race condition, we must delete the old undo log records.
We do this lazily by assigning a new table ID, so that the table lookup
for the old undo log records will fail.
dict_table_t::reassign_id(): Reassign the table_id to
effectively lazily delete old undo log records.
innobase_instant_try(): Invoke index->table->reassign_id() before
index->clear_instant_alter().
dict_index_t::clear_instant_alter(): Remove a loop that became
redundant in commit ae2004c616
and caused corruption of n_nullable when dropping the last column
which was not declared NOT NULL.
dict_index_t::clear_instant_alter(): Correctly move all fields
corresponding to instantly dropped columns to the end of the array.
This fixes a regression that was introduced in
commit 5aaee3746e.
We don't have many bits left, no need to add another InnoDB-specific flag.
Instead, we say that HA_REQUIRE_PRIMARY_KEY does not apply to SEQUENCE.
Meaning, if the engine declares HA_CAN_TABLES_WITHOUT_ROLLBACK (required
for SEQUENCE) it *must* support tables without a primary key.
recv_addr_trim(): Do not try to detach the hash bucket, because
the code for doing that does not always work.
recv_apply_hashed_log_recs(): Do not attempt to read pages for which
there exist no redo log records.
Remove some redundant declarations of global variables. These declarations
can refer to undefined type names, because they occur before any #include
statement for the type definitions. On GNU/Linux, uint and ulong seem to
be defined in <sys/types.h> due to _DEFAULT_SOURCE and __USE_MISC
becoming defined in <features.h>.
dict_index_t::db_trx_id(): Return the position of DB_TRX_ID.
Only valid for the clustered index.
dict_index_t::db_roll_ptr(): Return the position of DB_ROLL_PTR.
Only valid for the clustered index.
dict_index_get_sys_col_pos(): Remove. This was performing unnecessarily
complex computations, which only made sense for DB_ROW_ID, which would
exist either as the first field in the clustered index or as the last
field in a secondary index (only when a DB_ROW_ID column is materialised).
row_sel_store_row_id_to_prebuilt(): Remove, and replace with simpler code.
row_upd_index_entry_sys_field(): Remove.
btr_cur_log_sys(): Replaces row_upd_write_sys_vals_to_log().
btr_cur_write_sys(): Write DB_TRX_ID,DB_ROLL_PTR to a data tuple.