/************************************************************************* IMPORTANTNOTE:AnyoperationthatgeneratesredoMUSTcheckthatthere isenoughspaceintheredologbeforeforthatoperation.Thisis donebycallinglog_free_check().Thereasonforcheckingthe availabilityoftheredologspacebeforethestartoftheoperationis thatweMUSTnotholdanysynchonizationobjectswhenperformingthe check. Ifyoumakeachangeinthismodulemakesurethatnocodepathis
introduced where a call to log_free_check() is bypassed. */
/***************************************************************//**
Removes a clustered index record. The pcur in node was positioned on the
record, now it is detached.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_clust_rec( /*==========================*/
undo_node_t* node) /*!< in: undo node */
{
dberr_t err;
ulint n_tries = 0;
mtr_t mtr{node->trx};
dict_index_t* index = node->pcur.index();
table_id_t table_id = 0; constbool dict_locked = node->trx->dict_operation_lock_mode;
restart:
MDL_ticket* mdl_ticket = nullptr;
ut_ad(!table_id || dict_locked
|| !node->trx->dict_operation_lock_mode);
dict_table_t *table = table_id
? dict_table_open_on_id(table_id, dict_locked,
DICT_TABLE_OP_OPEN_ONLY_IF_CACHED,
node->trx->mysql_thd, &mdl_ticket)
: nullptr;
switch (node->table->id) { case DICT_COLUMNS_ID: /* This is rolling back an INSERT into SYS_COLUMNS. IfitwaspartofaninstantALTERTABLEoperation,we mustevictthetabledefinition,sothatitcanbe reloadedafterthedictionaryoperationhasbeen completed.Atthispoint,anycorrespondingoperation
to the metadata record will have been rolled back. */
ut_ad(node->trx->dict_operation_lock_mode);
ut_ad(node->rec_type == TRX_UNDO_INSERT_REC); if (rec_get_n_fields_old(rec)
!= DICT_NUM_FIELDS__SYS_COLUMNS
|| (rec_get_1byte_offs_flag(rec)
? rec_1_get_field_end_info(rec, 0) != 8
: rec_2_get_field_end_info(rec, 0) != 8)) { break;
}
static_assert(!DICT_FLD__SYS_COLUMNS__TABLE_ID, "");
node->trx->evict_table(mach_read_from_8(rec)); break; case DICT_INDEXES_ID:
ut_ad(node->trx->dict_operation_lock_mode);
ut_ad(node->rec_type == TRX_UNDO_INSERT_REC); if (!table_id) {
table_id = mach_read_from_8(rec); if (table_id) {
mtr.commit(); goto restart;
}
ut_ad("corrupted SYS_INDEXES record" == 0);
}
pfs_os_file_t d = OS_FILE_CLOSED;
const uint32_t space_id = dict_drop_index_tree(
&node->pcur, node->trx, &mtr); if (space_id) { if (table) {
lock_release_on_rollback(node->trx,
table); if (!dict_locked) {
dict_sys.lock(SRW_LOCK_CALL);
} if (table->release()) {
dict_sys.remove(table);
} elseif (table->space_id
== space_id) {
table->space = nullptr;
table->file_unreadable = true;
} if (!dict_locked) {
dict_sys.unlock();
}
table = nullptr; if (mdl_ticket) {
node->trx->mysql_thd->mdl_context
.release_lock(mdl_ticket);
mdl_ticket = nullptr;
}
}
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
retry: /* If did not succeed, try pessimistic descent to tree */
mtr.start(); if (index->table->is_temporary()) {
mtr.set_log_mode(MTR_LOG_NO_REDO);
} else {
index->set_modified(mtr);
}
ut_a(node->pcur.restore_position(BTR_PURGE_TREE, &mtr)
== btr_pcur_t::SAME_ALL);
func_exit: if (err == DB_SUCCESS && node->rec_type == TRX_UNDO_INSERT_METADATA) { /* When rolling back the very first instant ADD COLUMN
operation, reset the root page to the basic state. */
btr_reset_instant(*index, true, &mtr);
}
btr_pcur_commit_specify_mtr(&node->pcur, &mtr);
if (UNIV_LIKELY_NULL(table)) {
dict_table_close(table, node->trx->mysql_thd, mdl_ticket);
}
return(err);
}
/***************************************************************//**
Removes a secondary index entry if found.
@return DB_SUCCESS, DB_FAIL, or DB_OUT_OF_FILE_SPACE */ static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_sec_low( /*========================*/
btr_latch_mode mode, /*!< in: BTR_MODIFY_LEAF or BTR_MODIFY_TREE, dependingonwhetherwewishoptimisticor
pessimistic descent down the index tree */
dict_index_t* index, /*!< in: index */
dtuple_t* entry, /*!< in: index entry to remove */
que_thr_t* thr) /*!< in: query thread */
{
btr_pcur_t pcur;
dberr_t err = DB_SUCCESS;
mtr_t mtr{thr_get_trx(thr)}; constbool modify_leaf = mode == BTR_MODIFY_LEAF;
/***************************************************************//**
Removes a secondary index entry from the index if found. Tries first
optimistic, then pessimistic descent down the tree.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */ static MY_ATTRIBUTE((nonnull, warn_unused_result))
dberr_t
row_undo_ins_remove_sec( /*====================*/
dict_index_t* index, /*!< in: index */
dtuple_t* entry, /*!< in: index entry to insert */
que_thr_t* thr) /*!< in: query thread */
{
dberr_t err;
ulint n_tries = 0;
switch (node->rec_type) { default:
ut_ad("wrong undo record type" == 0); goto close_table; case TRX_UNDO_INSERT_METADATA: case TRX_UNDO_INSERT_REC: case TRX_UNDO_EMPTY: break; case TRX_UNDO_RENAME_TABLE:
dict_table_t* table = node->table;
ut_ad(!table->is_temporary());
ut_ad(table->file_unreadable
|| dict_table_is_file_per_table(table)
== !is_system_tablespace(table->space_id));
size_t len = mach_read_from_2(node->undo_rec)
- page_offset(ptr) - 2; const span<constchar> name(reinterpret_cast<constchar*>(ptr),
len); if (strlen(table->name.m_name) != len
|| memcmp(table->name.m_name, ptr, len)) {
dict_table_rename_in_cache(table, name, true);
} elseif (table->space && table->space->id) { constauto s = table->space->name(); if (len != s.size() || memcmp(ptr, s.data(), len)) {
table->rename_tablespace(name, true);
}
} goto close_table;
}
if (UNIV_UNLIKELY(!node->table->is_accessible())) {
close_table: /* Normally, tables should not disappear or become unaccessibleduringROLLBACK,becausetheyshouldbe protectedbyInnoDBtablelocks.Corruptioncouldbe avalidexception.
if (clust_index != NULL) { switch (node->rec_type) { case TRX_UNDO_INSERT_REC:
ptr = trx_undo_rec_get_row_ref(
ptr, clust_index, &node->ref,
node->heap); break; case TRX_UNDO_EMPTY:
node->ref = nullptr; returntrue; default:
node->ref = &trx_undo_metadata; if (!row_undo_search_clust_to_pcur(node)) { /* An error probably occurred during aninsertintotheclusteredindex,
after we wrote the undo log record. */ goto close_table;
} returntrue;
}
if (!row_undo_search_clust_to_pcur(node)) { /* An error probably occurred during aninsertintotheclusteredindex,
after we wrote the undo log record. */ goto close_table;
} if (node->table->n_v_cols) {
trx_undo_read_v_cols(node->table, ptr,
node->row, false);
}
} else {
ib::warn() << "Table " << node->table->name
<< " has no indexes," " ignoring the table"; goto close_table;
}
}
for (index = node->index; index;
index = dict_table_get_next_index(index)) { if (index->type & (DICT_FTS | DICT_CORRUPT)
|| !index->is_committed()) { continue;
}
/* An insert undo record TRX_UNDO_INSERT_REC will alwayscontainallfieldsoftheindex.Itdoesnot matterifanyindexeswerecreatedafterwards;all
index entries can be reconstructed from the row. */
dtuple_t* entry = row_build_index_entry(
node->row, node->ext, index, heap); if (UNIV_UNLIKELY(!entry)) { /* The database must have crashed after insertingaclusteredindexrecordbutbefore writingalltheexternallystoredcolumnsof thatrecord,orastatementisbeingrolled backbecauseanerroroccurredwhilestoring off-pagecolumns.
/***********************************************************//**
Undoes a fresh insert of a row to a table. A fresh insert means that
the same clustered index unique key did not have any record, even delete
marked, at the time of the insert. InnoDB is eager in a rollback: if it figures out that an index record will be removed in the purge
anyway, it will remove it in the rollback.
@return DB_SUCCESS or DB_OUT_OF_FILE_SPACE */
dberr_t
row_undo_ins( /*=========*/
undo_node_t* node, /*!< in: row undo node */
que_thr_t* thr) /*!< in: query thread */
{
dberr_t err; constbool dict_locked = node->trx->dict_operation_lock_mode;
if (!row_undo_ins_parse_undo_rec(node, dict_locked)) { return DB_SUCCESS;
}
switch (node->rec_type) { default:
ut_ad("wrong undo record type" == 0); /* fall through */ case TRX_UNDO_INSERT_REC: /* Skip the clustered index (the first index) */
node->index = dict_table_get_next_index(node->index);
if (err == DB_SUCCESS && node->table->stat_initialized()) { /* Not protected by dict_sys.latch ortable->stats_mutex_lock()for performancereasons,wewouldrathergetgarbage instat_n_rows(whichisjustanestimateanyway)
than protecting the following code with a latch. */
dict_table_n_rows_dec(node->table);
/* Do not attempt to update statistics when executingROLLBACKintheInnoDBSQL interpreter,becauseinthatcasewewould alreadybeholdingdict_sys.latch,which
would be acquired when updating statistics. */ if (!dict_locked) {
dict_stats_update_if_needed(node->table,
*node->trx);
}
} break;
case TRX_UNDO_INSERT_METADATA:
log_free_check();
ut_ad(!node->table->is_temporary());
err = row_undo_ins_remove_clust_rec(node); break; case TRX_UNDO_EMPTY:
err = node->table->clear(thr); break;
}
node->table->release();
node->table = NULL;
return(err);
}
Messung V0.5 in Prozent
¤ Dauer der Verarbeitung: 0.16 Sekunden
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.