Commit 4ff5311d authored by Marko Mäkelä's avatar Marko Mäkelä

MDEV-30100 preparation: Simplify InnoDB transaction commit further

trx_commit_complete_for_mysql(): Remove some conditions.
We will rely on trx_t::commit_lsn.

trx_t::must_flush_log_later: Remove. trx_commit_complete_for_mysql()
can simply check for trx_t::flush_log_later.

trx_t::commit_in_memory(): Set commit_lsn=0 if the log was written.

trx_flush_log_if_needed_low(): Renamed to trx_flush_log_if_needed().
Assert that innodb_flush_log_at_trx_commit!=0 was checked by
the caller and that the transaction is not in XA PREPARE state.
Unconditionally flush the log for data dictionary transactions,
to ensure the correct processing of ddl_recovery.log.

trx_write_serialisation_history(): Move some code from
trx_purge_add_undo_to_history().

trx_prepare(): Invoke log_write_up_to() directly if needed.

innobase_commit_ordered_2(): Simplify some conditions.
A read-write transaction will always carry nonzero trx_t::id.
Let us unconditionally reset mysql_log_file_name, flush_log_later
after trx_t::commit() was invoked.
parent f4bbea90
...@@ -4462,9 +4462,7 @@ innobase_commit_ordered_2( ...@@ -4462,9 +4462,7 @@ innobase_commit_ordered_2(
{ {
DBUG_ENTER("innobase_commit_ordered_2"); DBUG_ENTER("innobase_commit_ordered_2");
const bool read_only = trx->read_only || trx->id == 0; if (trx->id) {
if (!read_only) {
/* The following call reads the binary log position of /* The following call reads the binary log position of
the transaction being committed. the transaction being committed.
...@@ -4494,11 +4492,8 @@ innobase_commit_ordered_2( ...@@ -4494,11 +4492,8 @@ innobase_commit_ordered_2(
#endif /* WITH_WSREP */ #endif /* WITH_WSREP */
innobase_commit_low(trx); innobase_commit_low(trx);
trx->mysql_log_file_name = NULL;
if (!read_only) { trx->flush_log_later = false;
trx->mysql_log_file_name = NULL;
trx->flush_log_later = false;
}
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -181,13 +181,9 @@ note that the trx may have been committed before the caller acquires ...@@ -181,13 +181,9 @@ note that the trx may have been committed before the caller acquires
trx_t::mutex trx_t::mutex
@retval NULL if no match */ @retval NULL if no match */
trx_t* trx_get_trx_by_xid(const XID* xid); trx_t* trx_get_trx_by_xid(const XID* xid);
/**********************************************************************//** /** Durably write log until trx->commit_lsn
If required, flushes the log to disk if we called trx_commit_for_mysql() (if trx_t::commit_in_memory() was invoked with flush_log_later=true). */
with trx->flush_log_later == TRUE. */ void trx_commit_complete_for_mysql(trx_t *trx);
void
trx_commit_complete_for_mysql(
/*==========================*/
trx_t* trx); /*!< in/out: transaction */
/**********************************************************************//** /**********************************************************************//**
Marks the latest SQL statement ended. */ Marks the latest SQL statement ended. */
void void
...@@ -772,12 +768,6 @@ struct trx_t : ilist_node<> ...@@ -772,12 +768,6 @@ struct trx_t : ilist_node<>
defer flush of the logs to disk defer flush of the logs to disk
until after we release the until after we release the
mutex. */ mutex. */
bool must_flush_log_later;/*!< set in commit()
if flush_log_later was
set and redo log was written;
in that case we will
flush the log in
trx_commit_complete_for_mysql() */
ulint duplicates; /*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */ ulint duplicates; /*!< TRX_DUP_IGNORE | TRX_DUP_REPLACE */
/** whether this modifies InnoDB dictionary tables */ /** whether this modifies InnoDB dictionary tables */
bool dict_operation; bool dict_operation;
......
...@@ -268,12 +268,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr) ...@@ -268,12 +268,7 @@ trx_purge_add_undo_to_history(const trx_t* trx, trx_undo_t*& undo, mtr_t* mtr)
ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1); ut_ad(mach_read_from_2(undo_header + TRX_UNDO_NEEDS_PURGE) <= 1);
ut_ad(rseg->needs_purge > trx->id); ut_ad(rseg->needs_purge > trx->id);
ut_ad(rseg->last_page_no != FIL_NULL);
if (rseg->last_page_no == FIL_NULL)
{
rseg->last_page_no= undo->hdr_page_no;
rseg->set_last_commit(undo->hdr_offset, trx->rw_trx_hash_element->no);
}
rseg->history_size++; rseg->history_size++;
......
...@@ -419,7 +419,6 @@ void trx_t::free() ...@@ -419,7 +419,6 @@ void trx_t::free()
MEM_NOACCESS(&active_commit_ordered, sizeof active_commit_ordered); MEM_NOACCESS(&active_commit_ordered, sizeof active_commit_ordered);
MEM_NOACCESS(&check_unique_secondary, sizeof check_unique_secondary); MEM_NOACCESS(&check_unique_secondary, sizeof check_unique_secondary);
MEM_NOACCESS(&flush_log_later, sizeof flush_log_later); MEM_NOACCESS(&flush_log_later, sizeof flush_log_later);
MEM_NOACCESS(&must_flush_log_later, sizeof must_flush_log_later);
MEM_NOACCESS(&duplicates, sizeof duplicates); MEM_NOACCESS(&duplicates, sizeof duplicates);
MEM_NOACCESS(&dict_operation, sizeof dict_operation); MEM_NOACCESS(&dict_operation, sizeof dict_operation);
MEM_NOACCESS(&dict_operation_lock_mode, sizeof dict_operation_lock_mode); MEM_NOACCESS(&dict_operation_lock_mode, sizeof dict_operation_lock_mode);
...@@ -993,12 +992,14 @@ static void trx_write_serialisation_history(trx_t *trx, mtr_t *mtr) ...@@ -993,12 +992,14 @@ static void trx_write_serialisation_history(trx_t *trx, mtr_t *mtr)
{ {
mysql_mutex_lock(&purge_sys.pq_mutex); mysql_mutex_lock(&purge_sys.pq_mutex);
trx_sys.assign_new_trx_no(trx); trx_sys.assign_new_trx_no(trx);
const trx_id_t end{trx->rw_trx_hash_element->no};
/* If the rollback segment is not empty, trx->no cannot be less /* If the rollback segment is not empty, trx->no cannot be less
than any trx_t::no already in rseg. User threads only produce than any trx_t::no already in rseg. User threads only produce
events when a rollback segment is empty. */ events when a rollback segment is empty. */
purge_sys.purge_queue.push(TrxUndoRsegs(trx->rw_trx_hash_element->no, purge_sys.purge_queue.push(TrxUndoRsegs{end, *rseg});
*rseg));
mysql_mutex_unlock(&purge_sys.pq_mutex); mysql_mutex_unlock(&purge_sys.pq_mutex);
rseg->last_page_no= undo->hdr_page_no;
rseg->set_last_commit(undo->hdr_offset, end);
} }
else else
trx_sys.assign_new_trx_no(trx); trx_sys.assign_new_trx_no(trx);
...@@ -1086,50 +1087,30 @@ extern "C" void thd_decrement_pending_ops(MYSQL_THD); ...@@ -1086,50 +1087,30 @@ extern "C" void thd_decrement_pending_ops(MYSQL_THD);
@param trx transaction; if trx->state is PREPARED, the function will @param trx transaction; if trx->state is PREPARED, the function will
also wait for the flush to complete. also wait for the flush to complete.
*/ */
static void trx_flush_log_if_needed_low(lsn_t lsn, const trx_t *trx) static void trx_flush_log_if_needed(lsn_t lsn, trx_t *trx)
{ {
if (!srv_flush_log_at_trx_commit) ut_ad(srv_flush_log_at_trx_commit);
return; ut_ad(trx->state != TRX_STATE_PREPARED);
if (log_sys.get_flushed_lsn() > lsn) if (log_sys.get_flushed_lsn() > lsn)
return; return;
const bool flush= srv_file_flush_method != SRV_NOSYNC && const bool flush= trx->dict_operation ||
(srv_flush_log_at_trx_commit & 1); (srv_file_flush_method != SRV_NOSYNC &&
(srv_flush_log_at_trx_commit & 1));
if (trx->state == TRX_STATE_PREPARED)
{
/* XA, which is used with binlog as well.
Be conservative, use synchronous wait.*/
sync:
log_write_up_to(lsn, flush);
return;
}
completion_callback cb; completion_callback cb;
if ((cb.m_param = thd_increment_pending_ops(trx->mysql_thd))) if ((cb.m_param= thd_increment_pending_ops(trx->mysql_thd)))
{ {
cb.m_callback = (void (*)(void *)) thd_decrement_pending_ops; cb.m_callback = (void (*)(void *)) thd_decrement_pending_ops;
log_write_up_to(lsn, flush, false, &cb); log_write_up_to(lsn, flush, false, &cb);
} }
else else
goto sync; {
} trx->op_info= "flushing log";
log_write_up_to(lsn, flush);
/**********************************************************************//** trx->op_info= "";
If required, flushes the log to disk based on the value of }
innodb_flush_log_at_trx_commit. */
static
void
trx_flush_log_if_needed(
/*====================*/
lsn_t lsn, /*!< in: lsn up to which logs are to be
flushed. */
trx_t* trx) /*!< in/out: transaction */
{
trx->op_info = "flushing log";
trx_flush_log_if_needed_low(lsn, trx);
trx->op_info = "";
} }
/** Process tables that were modified by the committing transaction. */ /** Process tables that were modified by the committing transaction. */
...@@ -1239,7 +1220,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr) ...@@ -1239,7 +1220,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
{ {
/* We already detached from rseg in trx_write_serialisation_history() */ /* We already detached from rseg in trx_write_serialisation_history() */
ut_ad(!rsegs.m_redo.undo); ut_ad(!rsegs.m_redo.undo);
must_flush_log_later= false;
read_view.close(); read_view.close();
if (is_autocommit_non_locking()) if (is_autocommit_non_locking())
...@@ -1342,13 +1322,11 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr) ...@@ -1342,13 +1322,11 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
gathering. */ gathering. */
commit_lsn= undo_no || !xid.is_null() ? mtr->commit_lsn() : 0; commit_lsn= undo_no || !xid.is_null() ? mtr->commit_lsn() : 0;
if (!commit_lsn) if (commit_lsn && !flush_log_later && srv_flush_log_at_trx_commit)
/* Nothing to be done. */; {
else if (flush_log_later)
/* Do nothing yet */
must_flush_log_later= true;
else if (srv_flush_log_at_trx_commit)
trx_flush_log_if_needed(commit_lsn, this); trx_flush_log_if_needed(commit_lsn, this);
commit_lsn= 0;
}
} }
savepoints_discard(); savepoints_discard();
...@@ -1595,24 +1573,21 @@ trx_commit_for_mysql( ...@@ -1595,24 +1573,21 @@ trx_commit_for_mysql(
return(DB_CORRUPTION); return(DB_CORRUPTION);
} }
/**********************************************************************//** /** Durably write log until trx->commit_lsn
If required, flushes the log to disk if we called trx_commit_for_mysql() (if trx_t::commit_in_memory() was invoked with flush_log_later=true). */
with trx->flush_log_later == TRUE. */ void trx_commit_complete_for_mysql(trx_t *trx)
void
trx_commit_complete_for_mysql(
/*==========================*/
trx_t* trx) /*!< in/out: transaction */
{ {
if (trx->id != 0 const lsn_t lsn= trx->commit_lsn;
|| !trx->must_flush_log_later if (!lsn)
|| (srv_flush_log_at_trx_commit == 1 && trx->active_commit_ordered)) { return;
switch (srv_flush_log_at_trx_commit) {
return; case 0:
} return;
case 1:
trx_flush_log_if_needed(trx->commit_lsn, trx); if (trx->active_commit_ordered)
return;
trx->must_flush_log_later = false; }
trx_flush_log_if_needed(lsn, trx);
} }
/**********************************************************************//** /**********************************************************************//**
...@@ -1873,8 +1848,10 @@ trx_prepare( ...@@ -1873,8 +1848,10 @@ trx_prepare(
gather behind one doing the physical log write to disk. gather behind one doing the physical log write to disk.
We must not be holding any mutexes or latches here. */ We must not be holding any mutexes or latches here. */
if (auto f = srv_flush_log_at_trx_commit) {
trx_flush_log_if_needed(lsn, trx); log_write_up_to(lsn, (f & 1) && srv_file_flush_method
!= SRV_NOSYNC);
}
if (!UT_LIST_GET_LEN(trx->lock.trx_locks) if (!UT_LIST_GET_LEN(trx->lock.trx_locks)
|| trx->isolation_level == TRX_ISO_SERIALIZABLE) { || trx->isolation_level == TRX_ISO_SERIALIZABLE) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment