Skip to content

Commit f4bbea9

Browse files
committed
MDEV-30100 preparation: Simplify InnoDB transaction commit
trx_commit_cleanup(): Clean up any temporary undo log. Replaces trx_undo_commit_cleanup() and trx_undo_seg_free(). trx_write_serialisation_history(): Commit the mini-transaction. Do not touch temporary undo logs. Assume that a persistent rollback segment has been assigned. trx_serialise(): Merged into trx_write_serialisation_history(). trx_t::commit_low(): Correct some comments and assertions. trx_t::commit_persist(): Only invoke commit_low() on a mini-transaction if the persistent state needs to change.
1 parent eda75ca commit f4bbea9

File tree

4 files changed

+104
-174
lines changed

4 files changed

+104
-174
lines changed

storage/innobase/handler/handler0alter.cc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11498,7 +11498,7 @@ ha_innobase::commit_inplace_alter_table(
1149811498
DEBUG_SYNC(m_user_thd, "innodb_alter_inplace_before_commit");
1149911499

1150011500
if (new_clustered) {
11501-
ut_ad(trx->has_logged());
11501+
ut_ad(trx->has_logged_persistent());
1150211502
for (inplace_alter_handler_ctx** pctx = ctx_array; *pctx;
1150311503
pctx++) {
1150411504
auto ctx= static_cast<ha_innobase_inplace_ctx*>(*pctx);

storage/innobase/include/trx0undo.h

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -226,12 +226,6 @@ void trx_undo_set_state_at_prepare(trx_t *trx, trx_undo_t *undo, bool rollback,
226226
mtr_t *mtr)
227227
MY_ATTRIBUTE((nonnull));
228228

229-
/** Free temporary undo log after commit or rollback.
230-
The information is not needed after a commit or rollback, therefore
231-
the data can be discarded.
232-
@param undo temporary undo log */
233-
void trx_undo_commit_cleanup(trx_undo_t *undo);
234-
235229
/** At shutdown, frees the undo logs of a transaction. */
236230
void
237231
trx_undo_free_at_shutdown(trx_t *trx);

storage/innobase/trx/trx0trx.cc

Lines changed: 103 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -969,93 +969,50 @@ trx_start_low(
969969
ut_a(trx->error_state == DB_SUCCESS);
970970
}
971971

972-
/** Set the serialisation number for a persistent committed transaction.
973-
@param[in,out] trx committed transaction with persistent changes */
974-
static
975-
void
976-
trx_serialise(trx_t* trx)
977-
{
978-
trx_rseg_t *rseg = trx->rsegs.m_redo.rseg;
979-
ut_ad(rseg);
980-
981-
if (rseg->last_page_no == FIL_NULL) {
982-
mysql_mutex_lock(&purge_sys.pq_mutex);
983-
}
984-
985-
trx_sys.assign_new_trx_no(trx);
986-
987-
/* If the rollback segment is not empty then the
988-
new trx_t::no can't be less than any trx_t::no
989-
already in the rollback segment. User threads only
990-
produce events when a rollback segment is empty. */
991-
if (rseg->last_page_no == FIL_NULL) {
992-
purge_sys.purge_queue.push(TrxUndoRsegs(trx->rw_trx_hash_element->no,
993-
*rseg));
994-
mysql_mutex_unlock(&purge_sys.pq_mutex);
995-
}
996-
}
997-
998-
/****************************************************************//**
999-
Assign the transaction its history serialisation number and write the
1000-
update UNDO log record to the assigned rollback segment. */
1001-
static
1002-
void
1003-
trx_write_serialisation_history(
1004-
/*============================*/
1005-
trx_t* trx, /*!< in/out: transaction */
1006-
mtr_t* mtr) /*!< in/out: mini-transaction */
972+
/** Assign the transaction its history serialisation number and write the
973+
UNDO log to the assigned rollback segment.
974+
@param trx persistent transaction
975+
@param mtr mini-transaction */
976+
static void trx_write_serialisation_history(trx_t *trx, mtr_t *mtr)
1007977
{
1008-
/* Change the undo log segment states from TRX_UNDO_ACTIVE to some
1009-
other state: these modifications to the file data structure define
1010-
the transaction as committed in the file based domain, at the
1011-
serialization point of the log sequence number lsn obtained below. */
1012-
1013-
/* We have to hold the rseg mutex because update log headers have
1014-
to be put to the history list in the (serialisation) order of the
1015-
UNDO trx number. This is required for the purge in-memory data
1016-
structures too. */
1017-
1018-
if (trx_undo_t* undo = trx->rsegs.m_noredo.undo) {
1019-
/* Undo log for temporary tables is discarded at transaction
1020-
commit. There is no purge for temporary tables, and also no
1021-
MVCC, because they are private to a session. */
1022-
1023-
mtr_t temp_mtr;
1024-
temp_mtr.start();
1025-
temp_mtr.set_log_mode(MTR_LOG_NO_REDO);
1026-
buf_block_t* block= buf_page_get(page_id_t(SRV_TMP_SPACE_ID,
1027-
undo->hdr_page_no),
1028-
0, RW_X_LATCH, mtr);
1029-
ut_a(block);
1030-
temp_mtr.write<2>(*block, TRX_UNDO_SEG_HDR + TRX_UNDO_STATE
1031-
+ block->page.frame, TRX_UNDO_TO_PURGE);
1032-
undo->state = TRX_UNDO_TO_PURGE;
1033-
temp_mtr.commit();
1034-
}
1035-
1036-
trx_rseg_t* rseg = trx->rsegs.m_redo.rseg;
1037-
if (!rseg) {
1038-
ut_ad(!trx->rsegs.m_redo.undo);
1039-
return;
1040-
}
1041-
1042-
trx_undo_t*& undo = trx->rsegs.m_redo.undo;
1043-
1044-
ut_ad(!trx->read_only);
1045-
1046-
/* Assign the transaction serialisation number and add any
1047-
undo log to the purge queue. */
1048-
if (undo) {
1049-
rseg->latch.wr_lock(SRW_LOCK_CALL);
1050-
ut_ad(undo->rseg == rseg);
1051-
trx_serialise(trx);
1052-
UT_LIST_REMOVE(rseg->undo_list, undo);
1053-
trx_purge_add_undo_to_history(trx, undo, mtr);
1054-
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
1055-
rseg->latch.wr_unlock();
1056-
}
1057-
1058-
rseg->release();
978+
ut_ad(!trx->read_only);
979+
trx_rseg_t *rseg= trx->rsegs.m_redo.rseg;
980+
trx_undo_t *&undo= trx->rsegs.m_redo.undo;
981+
if (UNIV_LIKELY(undo != nullptr))
982+
{
983+
MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
984+
985+
/* We have to hold exclusive rseg->latch because undo log headers have
986+
to be put to the history list in the (serialisation) order of the
987+
UNDO trx number. This is required for purge_sys too. */
988+
rseg->latch.wr_lock(SRW_LOCK_CALL);
989+
ut_ad(undo->rseg == rseg);
990+
/* Assign the transaction serialisation number and add any
991+
undo log to the purge queue. */
992+
if (rseg->last_page_no == FIL_NULL)
993+
{
994+
mysql_mutex_lock(&purge_sys.pq_mutex);
995+
trx_sys.assign_new_trx_no(trx);
996+
/* If the rollback segment is not empty, trx->no cannot be less
997+
than any trx_t::no already in rseg. User threads only produce
998+
events when a rollback segment is empty. */
999+
purge_sys.purge_queue.push(TrxUndoRsegs(trx->rw_trx_hash_element->no,
1000+
*rseg));
1001+
mysql_mutex_unlock(&purge_sys.pq_mutex);
1002+
}
1003+
else
1004+
trx_sys.assign_new_trx_no(trx);
1005+
UT_LIST_REMOVE(rseg->undo_list, undo);
1006+
/* Change the undo log segment state from TRX_UNDO_ACTIVE, to
1007+
define the transaction as committed in the file based domain,
1008+
at mtr->commit_lsn() obtained in mtr->commit() below. */
1009+
trx_purge_add_undo_to_history(trx, undo, mtr);
1010+
rseg->release();
1011+
rseg->latch.wr_unlock();
1012+
}
1013+
else
1014+
rseg->release();
1015+
mtr->commit();
10591016
}
10601017

10611018
/********************************************************************
@@ -1229,6 +1186,55 @@ void trx_t::evict_table(table_id_t table_id, bool reset_only)
12291186
}
12301187
}
12311188

1189+
/** Free temporary undo log after commit or rollback.
1190+
@param undo temporary undo log */
1191+
ATTRIBUTE_NOINLINE static void trx_commit_cleanup(trx_undo_t *&undo)
1192+
{
1193+
trx_rseg_t *const rseg= undo->rseg;
1194+
ut_ad(rseg->space == fil_system.temp_space);
1195+
rseg->latch.wr_lock(SRW_LOCK_CALL);
1196+
UT_LIST_REMOVE(rseg->undo_list, undo);
1197+
ut_ad(undo->state == TRX_UNDO_ACTIVE || undo->state == TRX_UNDO_PREPARED);
1198+
ut_ad(undo->id < TRX_RSEG_N_SLOTS);
1199+
/* Delete first the undo log segment in the file */
1200+
bool finished;
1201+
mtr_t mtr;
1202+
do
1203+
{
1204+
mtr.start();
1205+
mtr.set_log_mode(MTR_LOG_NO_REDO);
1206+
1207+
finished= true;
1208+
1209+
if (buf_block_t *block=
1210+
buf_page_get(page_id_t(SRV_TMP_SPACE_ID, undo->hdr_page_no), 0,
1211+
RW_X_LATCH, &mtr))
1212+
{
1213+
fseg_header_t *file_seg= TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +
1214+
block->page.frame;
1215+
1216+
finished= fseg_free_step(file_seg, &mtr);
1217+
1218+
if (!finished);
1219+
else if (buf_block_t *rseg_header= rseg->get(&mtr, nullptr))
1220+
{
1221+
static_assert(FIL_NULL == 0xffffffff, "compatibility");
1222+
memset(rseg_header->page.frame + TRX_RSEG + TRX_RSEG_UNDO_SLOTS +
1223+
undo->id * TRX_RSEG_SLOT_SIZE, 0xff, 4);
1224+
}
1225+
}
1226+
1227+
mtr.commit();
1228+
}
1229+
while (!finished);
1230+
1231+
ut_ad(rseg->curr_size > undo->size);
1232+
rseg->curr_size-= undo->size;
1233+
rseg->latch.wr_unlock();
1234+
ut_free(undo);
1235+
undo= nullptr;
1236+
}
1237+
12321238
TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
12331239
{
12341240
/* We already detached from rseg in trx_write_serialisation_history() */
@@ -1300,15 +1306,14 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
13001306
release_locks();
13011307
}
13021308

1303-
if (mtr)
1309+
if (trx_undo_t *&undo= rsegs.m_noredo.undo)
13041310
{
1305-
if (trx_undo_t *&undo= rsegs.m_noredo.undo)
1306-
{
1307-
ut_ad(undo->rseg == rsegs.m_noredo.rseg);
1308-
trx_undo_commit_cleanup(undo);
1309-
undo= nullptr;
1310-
}
1311+
ut_ad(undo->rseg == rsegs.m_noredo.rseg);
1312+
trx_commit_cleanup(undo);
1313+
}
13111314

1315+
if (mtr)
1316+
{
13121317
/* NOTE that we could possibly make a group commit more efficient
13131318
here: call std::this_thread::yield() here to allow also other trxs to come
13141319
to commit! */
@@ -1346,8 +1351,6 @@ TRANSACTIONAL_INLINE inline void trx_t::commit_in_memory(const mtr_t *mtr)
13461351
trx_flush_log_if_needed(commit_lsn, this);
13471352
}
13481353

1349-
ut_ad(!rsegs.m_noredo.undo);
1350-
13511354
savepoints_discard();
13521355

13531356
if (fts_trx)
@@ -1390,7 +1393,7 @@ TRANSACTIONAL_TARGET void trx_t::commit_low(mtr_t *mtr)
13901393
{
13911394
ut_ad(!mtr || mtr->is_active());
13921395
ut_d(bool aborted= in_rollback && error_state == DB_DEADLOCK);
1393-
ut_ad(!mtr == (aborted || !has_logged()));
1396+
ut_ad(!mtr == (aborted || !has_logged_persistent()));
13941397
ut_ad(!mtr || !aborted);
13951398

13961399
if (fts_trx && undo_no)
@@ -1416,24 +1419,19 @@ TRANSACTIONAL_TARGET void trx_t::commit_low(mtr_t *mtr)
14161419
{
14171420
if (UNIV_UNLIKELY(apply_online_log))
14181421
apply_log();
1419-
trx_write_serialisation_history(this, mtr);
14201422

14211423
/* The following call commits the mini-transaction, making the
14221424
whole transaction committed in the file-based world, at this log
14231425
sequence number. The transaction becomes 'durable' when we write
14241426
the log to disk, but in the logical sense the commit in the
14251427
file-based data structures (undo logs etc.) happens here.
14261428
1427-
NOTE that transaction numbers, which are assigned only to
1428-
transactions with an update undo log, do not necessarily come in
1429+
NOTE that transaction numbers do not necessarily come in
14291430
exactly the same order as commit lsn's, if the transactions have
1430-
different rollback segments. To get exactly the same order we
1431-
should hold the kernel mutex up to this point, adding to the
1432-
contention of the kernel mutex. However, if a transaction T2 is
1431+
different rollback segments. However, if a transaction T2 is
14331432
able to see modifications made by a transaction T1, T2 will always
14341433
get a bigger transaction number and a bigger commit lsn than T1. */
1435-
1436-
mtr->commit();
1434+
trx_write_serialisation_history(this, mtr);
14371435
}
14381436
else if (trx_rseg_t *rseg= rsegs.m_redo.rseg)
14391437
{
@@ -1456,7 +1454,7 @@ void trx_t::commit_persist()
14561454
mtr_t *mtr= nullptr;
14571455
mtr_t local_mtr;
14581456

1459-
if (has_logged())
1457+
if (has_logged_persistent())
14601458
{
14611459
mtr= &local_mtr;
14621460
local_mtr.start();

storage/innobase/trx/trx0undo.cc

Lines changed: 0 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -961,47 +961,6 @@ trx_undo_truncate_start(
961961
goto loop;
962962
}
963963

964-
/** Frees an undo log segment which is not in the history list.
965-
@param undo temporary undo log */
966-
static void trx_undo_seg_free(const trx_undo_t *undo)
967-
{
968-
ut_ad(undo->id < TRX_RSEG_N_SLOTS);
969-
970-
trx_rseg_t *const rseg= undo->rseg;
971-
bool finished;
972-
mtr_t mtr;
973-
ut_ad(rseg->space == fil_system.temp_space);
974-
975-
do
976-
{
977-
mtr.start();
978-
mtr.set_log_mode(MTR_LOG_NO_REDO);
979-
980-
finished= true;
981-
982-
if (buf_block_t *block=
983-
buf_page_get(page_id_t(SRV_TMP_SPACE_ID, undo->hdr_page_no), 0,
984-
RW_X_LATCH, &mtr))
985-
{
986-
fseg_header_t *file_seg= TRX_UNDO_SEG_HDR + TRX_UNDO_FSEG_HEADER +
987-
block->page.frame;
988-
989-
finished= fseg_free_step(file_seg, &mtr);
990-
991-
if (!finished);
992-
else if (buf_block_t* rseg_header = rseg->get(&mtr, nullptr))
993-
{
994-
static_assert(FIL_NULL == 0xffffffff, "compatibility");
995-
mtr.memset(rseg_header, TRX_RSEG + TRX_RSEG_UNDO_SLOTS +
996-
undo->id * TRX_RSEG_SLOT_SIZE, 4, 0xff);
997-
}
998-
}
999-
1000-
mtr.commit();
1001-
}
1002-
while (!finished);
1003-
}
1004-
1005964
/*========== UNDO LOG MEMORY COPY INITIALIZATION =====================*/
1006965

1007966
/** Read an undo log when starting up the database.
@@ -1508,27 +1467,6 @@ void trx_undo_set_state_at_prepare(trx_t *trx, trx_undo_t *undo, bool rollback,
15081467
trx_undo_write_xid(block, offset, undo->xid, mtr);
15091468
}
15101469

1511-
/** Free temporary undo log after commit or rollback.
1512-
The information is not needed after a commit or rollback, therefore
1513-
the data can be discarded.
1514-
@param undo temporary undo log */
1515-
void trx_undo_commit_cleanup(trx_undo_t *undo)
1516-
{
1517-
trx_rseg_t *rseg= undo->rseg;
1518-
ut_ad(rseg->space == fil_system.temp_space);
1519-
rseg->latch.wr_lock(SRW_LOCK_CALL);
1520-
1521-
UT_LIST_REMOVE(rseg->undo_list, undo);
1522-
ut_ad(undo->state == TRX_UNDO_TO_PURGE);
1523-
/* Delete first the undo log segment in the file */
1524-
trx_undo_seg_free(undo);
1525-
ut_ad(rseg->curr_size > undo->size);
1526-
rseg->curr_size-= undo->size;
1527-
1528-
rseg->latch.wr_unlock();
1529-
ut_free(undo);
1530-
}
1531-
15321470
/** At shutdown, frees the undo logs of a transaction. */
15331471
void trx_undo_free_at_shutdown(trx_t *trx)
15341472
{

0 commit comments

Comments
 (0)