From 72959475089fc0923d49e2357ff4ecb8bdf7c98a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marko=20M=C3=A4kel=C3=A4?= <marko.makela@mariadb.com>
Date: Tue, 14 Mar 2017 12:03:30 +0200
Subject: [PATCH] MDEV-12288 Reset DB_TRX_ID when the history is removed, to
 speed up MVCC

This is a port of a proof-of-concept patch to MySQL 5.7.17.
NOTE: this is changing the InnoDB file format! The patched InnoDB
is not compatible with normal InnoDB files!

The InnoDB clustered index record system columns DB_TRX_ID,DB_ROLL_PTR
are used by multi-versioning. After the history is no longer needed, these
columns can safely be reset to 0 and 1<<55 (to indicate a fresh insert).

Merge insert_undo and update_undo into a single log.
Always initialize the TRX_UNDO_PAGE_TYPE to 0. Remove undo->type.

MLOG_UNDO_HDR_REUSE: Remove. This changes the redo log format!

row_purge_reset_trx_id(): New function to reset the columns.
This will be called for all update_undo processing in purge
that does not remove the clustered index record.
FIXME: Write redo log for ROW_FORMAT=COMPRESSED tables too!

trx_undo_update_rec_get_update(): Allow trx_id=0 when copying the
old DB_TRX_ID of the record to the undo log.

ReadView::changes_visible(): Allow id==0. (Return true for it.)

row_vers_impl_x_locked_low(), row_vers_build_for_semi_consistent_read():
Implement a fast path for DB_TRX_ID=0.
---
 extra/innochecksum.cc                              |  33 +-
 .../suite/innodb_zip/r/innochecksum_3.result       |   4 +-
 storage/innobase/buf/buf0buf.cc                    |  16 +-
 storage/innobase/include/mtr0types.h               |   3 -
 storage/innobase/include/read0types.h              |   2 -
 storage/innobase/include/trx0purge.h               |   5 -
 storage/innobase/include/trx0roll.h                |  33 +-
 storage/innobase/include/trx0rseg.h                |  18 +-
 storage/innobase/include/trx0trx.h                 |   6 +-
 storage/innobase/include/trx0trx.ic                |  18 +-
 storage/innobase/include/trx0undo.h                | 135 ++---
 storage/innobase/log/log0log.cc                    |   2 +-
 storage/innobase/log/log0recv.cc                   |   7 +-
 storage/innobase/row/row0import.cc                 |   8 +-
 storage/innobase/row/row0purge.cc                  | 168 ++++--
 storage/innobase/row/row0trunc.cc                  |   6 +-
 storage/innobase/row/row0undo.cc                   |   2 +-
 storage/innobase/row/row0upd.cc                    |   3 +-
 storage/innobase/row/row0vers.cc                   |  17 +
 storage/innobase/trx/trx0purge.cc                  |  44 +-
 storage/innobase/trx/trx0rec.cc                    | 172 ++----
 storage/innobase/trx/trx0roll.cc                   | 165 ++----
 storage/innobase/trx/trx0rseg.cc                   |  26 +-
 storage/innobase/trx/trx0sys.cc                    |   8 +-
 storage/innobase/trx/trx0trx.cc                    | 538 ++++-------------
 storage/innobase/trx/trx0undo.cc                   | 644 ++++++---------------
 26 files changed, 626 insertions(+), 1457 deletions(-)

diff --git a/extra/innochecksum.cc b/extra/innochecksum.cc
index 57586ebee95..b5c247190cf 100644
--- a/extra/innochecksum.cc
+++ b/extra/innochecksum.cc
@@ -115,9 +115,6 @@ struct innodb_page_type {
 	int n_undo_state_to_purge;
 	int n_undo_state_prepared;
 	int n_undo_state_other;
-	int n_undo_insert;
-	int n_undo_update;
-	int n_undo_other;
 	int n_fil_page_index;
 	int n_fil_page_undo_log;
 	int n_fil_page_inode;
@@ -644,26 +641,10 @@ parse_page(
 
 	case FIL_PAGE_UNDO_LOG:
 		page_type.n_fil_page_undo_log++;
-		undo_page_type = mach_read_from_2(page +
-				     TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE);
 		if (page_type_dump) {
 			fprintf(file, "#::%8" PRIuMAX "\t\t|\t\tUndo log page\t\t\t|",
 				cur_page_num);
 		}
-		if (undo_page_type == TRX_UNDO_INSERT) {
-			page_type.n_undo_insert++;
-			if (page_type_dump) {
-				fprintf(file, "\t%s",
-					"Insert Undo log page");
-			}
-
-		} else if (undo_page_type == TRX_UNDO_UPDATE) {
-			page_type.n_undo_update++;
-			if (page_type_dump) {
-				fprintf(file, "\t%s",
-					"Update undo log page");
-			}
-		}
 
 		undo_page_type = mach_read_from_2(page + TRX_UNDO_SEG_HDR +
 						  TRX_UNDO_STATE);
@@ -684,14 +665,6 @@ parse_page(
 				}
 				break;
 
-			case TRX_UNDO_TO_FREE:
-				page_type.n_undo_state_to_free++;
-				if (page_type_dump) {
-					fprintf(file, ", %s", "Insert undo "
-						"segment that can be freed");
-				}
-				break;
-
 			case TRX_UNDO_TO_PURGE:
 				page_type.n_undo_state_to_purge++;
 				if (page_type_dump) {
@@ -893,10 +866,8 @@ print_summary(
 		page_type.n_fil_page_type_other);
 	fprintf(fil_out, "\n===============================================\n");
 	fprintf(fil_out, "Additional information:\n");
-	fprintf(fil_out, "Undo page type: %d insert, %d update, %d other\n",
-		page_type.n_undo_insert,
-		page_type.n_undo_update,
-		page_type.n_undo_other);
+	fprintf(fil_out, "Undo page type: %d\n",
+		page_type.n_fil_page_undo_log);
 	fprintf(fil_out, "Undo page state: %d active, %d cached, %d to_free, %d"
 		" to_purge, %d prepared, %d other\n",
 		page_type.n_undo_state_active,
diff --git a/mysql-test/suite/innodb_zip/r/innochecksum_3.result b/mysql-test/suite/innodb_zip/r/innochecksum_3.result
index 85058c41e04..c39cf59de32 100644
--- a/mysql-test/suite/innodb_zip/r/innochecksum_3.result
+++ b/mysql-test/suite/innodb_zip/r/innochecksum_3.result
@@ -109,7 +109,7 @@ File::tab#.ibd
        #	Other type of page
 ===============================================
 Additional information:
-Undo page type: # insert, # update, # other
+Undo page type: #
 Undo page state: # active, # cached, # to_free, # to_purge, # prepared, # other
 [3]: Check the page type summary with longform for tab1.ibd
 
@@ -132,7 +132,7 @@ File::tab#.ibd
        #	Other type of page
 ===============================================
 Additional information:
-Undo page type: # insert, # update, # other
+Undo page type: #
 Undo page state: # active, # cached, # to_free, # to_purge, # prepared, # other
 [4]: Page type dump for  with longform for tab1.ibd
 # Print the contents stored in dump.txt
diff --git a/storage/innobase/buf/buf0buf.cc b/storage/innobase/buf/buf0buf.cc
index fe30630a198..a5c28f3b948 100644
--- a/storage/innobase/buf/buf0buf.cc
+++ b/storage/innobase/buf/buf0buf.cc
@@ -1270,19 +1270,6 @@ buf_page_print(
 				read_buf + FIL_PAGE_ARCH_LOG_NO_OR_SPACE_ID);
 	}
 
-#ifndef UNIV_HOTBACKUP
-	if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE)
-	    == TRX_UNDO_INSERT) {
-		fprintf(stderr,
-			"InnoDB: Page may be an insert undo log page\n");
-	} else if (mach_read_from_2(read_buf + TRX_UNDO_PAGE_HDR
-				    + TRX_UNDO_PAGE_TYPE)
-		   == TRX_UNDO_UPDATE) {
-		fprintf(stderr,
-			"InnoDB: Page may be an update undo log page\n");
-	}
-#endif /* !UNIV_HOTBACKUP */
-
 	switch (fil_page_get_type(read_buf)) {
 		index_id_t	index_id;
 	case FIL_PAGE_INDEX:
@@ -1302,6 +1289,9 @@ buf_page_print(
 		}
 #endif /* !UNIV_HOTBACKUP */
 		break;
+	case FIL_PAGE_UNDO_LOG:
+		fputs("InnoDB: Page may be an undo log page\n", stderr);
+		break;
 	case FIL_PAGE_INODE:
 		fputs("InnoDB: Page may be an 'inode' page\n", stderr);
 		break;
diff --git a/storage/innobase/include/mtr0types.h b/storage/innobase/include/mtr0types.h
index f15a6b2927e..bdf442ee671 100644
--- a/storage/innobase/include/mtr0types.h
+++ b/storage/innobase/include/mtr0types.h
@@ -111,9 +111,6 @@ enum mlog_id_t {
 	/** discard an update undo log header */
 	MLOG_UNDO_HDR_DISCARD = 23,
 
-	/** reuse an insert undo log header */
-	MLOG_UNDO_HDR_REUSE = 24,
-
 	/** create an undo log header */
 	MLOG_UNDO_HDR_CREATE = 25,
 
diff --git a/storage/innobase/include/read0types.h b/storage/innobase/include/read0types.h
index c83c7e04f11..8056dbf437f 100644
--- a/storage/innobase/include/read0types.h
+++ b/storage/innobase/include/read0types.h
@@ -163,8 +163,6 @@ public:
 		const table_name_t&	name) const
 		MY_ATTRIBUTE((warn_unused_result))
 	{
-		ut_ad(id > 0);
-
 		if (id < m_up_limit_id || id == m_creator_trx_id) {
 
 			return(true);
diff --git a/storage/innobase/include/trx0purge.h b/storage/innobase/include/trx0purge.h
index 8917169dc94..1627da5e04c 100644
--- a/storage/innobase/include/trx0purge.h
+++ b/storage/innobase/include/trx0purge.h
@@ -73,13 +73,8 @@ void
 trx_purge_add_update_undo_to_history(
 /*=================================*/
 	trx_t*		trx,		/*!< in: transaction */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: update undo log. */
 	page_t*		undo_page,	/*!< in: update undo log header page,
 					x-latched */
-	bool		update_rseg_history_len,
-					/*!< in: if true: update rseg history
-					len else skip updating it. */
-	ulint		n_added_logs,	/*!< in: number of logs added */
 	mtr_t*		mtr);		/*!< in: mtr */
 /*******************************************************************//**
 This function runs a purge batch.
diff --git a/storage/innobase/include/trx0roll.h b/storage/innobase/include/trx0roll.h
index ec4c7d57e5d..e687fe9a74c 100644
--- a/storage/innobase/include/trx0roll.h
+++ b/storage/innobase/include/trx0roll.h
@@ -50,32 +50,15 @@ trx_savept_t
 trx_savept_take(
 /*============*/
 	trx_t*	trx);	/*!< in: transaction */
-/********************************************************************//**
-Pops the topmost record when the two undo logs of a transaction are seen
-as a single stack of records ordered by their undo numbers.
-@return undo log record copied to heap, NULL if none left, or if the
-undo number of the top record would be less than the limit */
+/** Get the last undo log record of a transaction (for rollback).
+@param[in,out]	trx		transaction
+@param[out]	roll_ptr	DB_ROLL_PTR to the undo record
+@param[in,out]	heap		memory heap for allocation
+@return	undo log record copied to heap
+@retval	NULL if none left or the roll_limit (savepoint) was reached */
 trx_undo_rec_t*
-trx_roll_pop_top_rec_of_trx_low(
-/*============================*/
-	trx_t*		trx,		/*!< in/out: transaction */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: rollback segment to look
-					for next undo log record. */
-	undo_no_t	limit,		/*!< in: least undo number we need */
-	roll_ptr_t*	roll_ptr,	/*!< out: roll pointer to undo record */
-	mem_heap_t*	heap);		/*!< in/out: memory heap where copied */
-
-/********************************************************************//**
-Get next undo log record from redo and noredo rollback segments.
-@return undo log record copied to heap, NULL if none left, or if the
-undo number of the top record would be less than the limit */
-trx_undo_rec_t*
-trx_roll_pop_top_rec_of_trx(
-/*========================*/
-	trx_t*		trx,		/*!< in: transaction */
-	undo_no_t	limit,		/*!< in: least undo number we need */
-	roll_ptr_t*	roll_ptr,	/*!< out: roll pointer to undo record */
-	mem_heap_t*	heap);		/*!< in: memory heap where copied */
+trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap)
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
 
 /*******************************************************************//**
 Rollback or clean up any incomplete transactions which were
diff --git a/storage/innobase/include/trx0rseg.h b/storage/innobase/include/trx0rseg.h
index b9cbd387a62..a1c02bba735 100644
--- a/storage/innobase/include/trx0rseg.h
+++ b/storage/innobase/include/trx0rseg.h
@@ -185,20 +185,12 @@ struct trx_rseg_t {
 	ulint				curr_size;
 
 	/*--------------------------------------------------------*/
-	/* Fields for update undo logs */
-	/** List of update undo logs */
-	UT_LIST_BASE_NODE_T(trx_undo_t)	update_undo_list;
+	/* Fields for undo logs */
+	/** List of undo logs */
+	UT_LIST_BASE_NODE_T(trx_undo_t)	undo_list;
 
-	/** List of update undo log segments cached for fast reuse */
-	UT_LIST_BASE_NODE_T(trx_undo_t)	update_undo_cached;
-
-	/*--------------------------------------------------------*/
-	/* Fields for insert undo logs */
-	/** List of insert undo logs */
-	UT_LIST_BASE_NODE_T(trx_undo_t) insert_undo_list;
-
-	/** List of insert undo log segments cached for fast reuse */
-	UT_LIST_BASE_NODE_T(trx_undo_t) insert_undo_cached;
+	/** List of undo log segments cached for fast reuse */
+	UT_LIST_BASE_NODE_T(trx_undo_t)	undo_cached;
 
 	/*--------------------------------------------------------*/
 
diff --git a/storage/innobase/include/trx0trx.h b/storage/innobase/include/trx0trx.h
index 1a5f5b16855..d6c606d13d5 100644
--- a/storage/innobase/include/trx0trx.h
+++ b/storage/innobase/include/trx0trx.h
@@ -846,10 +846,8 @@ struct trx_undo_ptr_t {
 	trx_rseg_t*	rseg;		/*!< rollback segment assigned to the
 					transaction, or NULL if not assigned
 					yet */
-	trx_undo_t*	insert_undo;	/*!< pointer to the insert undo log, or
-					NULL if no inserts performed yet */
-	trx_undo_t*	update_undo;	/*!< pointer to the update undo log, or
-					NULL if no update performed yet */
+	trx_undo_t*	undo;		/*!< pointer to the undo log, or
+					NULL if nothing logged yet */
 };
 
 /** Rollback segments assigned to a transaction for undo logging. */
diff --git a/storage/innobase/include/trx0trx.ic b/storage/innobase/include/trx0trx.ic
index 7120a7aaced..73fe0883e78 100644
--- a/storage/innobase/include/trx0trx.ic
+++ b/storage/innobase/include/trx0trx.ic
@@ -221,20 +221,7 @@ trx_is_redo_rseg_updated(
 /*=====================*/
 	const trx_t*	   trx) /*!< in: transaction */
 {
-	return(trx->rsegs.m_redo.insert_undo != 0
-	       || trx->rsegs.m_redo.update_undo != 0);
-}
-
-/********************************************************************//**
-Check if noredo rseg is modified for insert/update. */
-UNIV_INLINE
-bool
-trx_is_noredo_rseg_updated(
-/*=======================*/
-	const trx_t*	   trx) /*!< in: transaction */
-{
-	return(trx->rsegs.m_noredo.insert_undo != 0
-	       || trx->rsegs.m_noredo.update_undo != 0);
+	return(trx->rsegs.m_redo.undo != 0);
 }
 
 /********************************************************************//**
@@ -245,8 +232,7 @@ trx_is_rseg_updated(
 /*================*/
 	const trx_t*	   trx) /*!< in: transaction */
 {
-	return(trx_is_redo_rseg_updated(trx)
-	       || trx_is_noredo_rseg_updated(trx));
+	return(trx->rsegs.m_redo.undo || trx->rsegs.m_noredo.undo);
 }
 
 /********************************************************************//**
diff --git a/storage/innobase/include/trx0undo.h b/storage/innobase/include/trx0undo.h
index f60a01693c4..ffe2927a2ff 100644
--- a/storage/innobase/include/trx0undo.h
+++ b/storage/innobase/include/trx0undo.h
@@ -206,61 +206,31 @@ trx_undo_get_first_rec(
 	ulint			mode,
 	mtr_t*			mtr);
 
-/********************************************************************//**
-Tries to add a page to the undo log segment where the undo log is placed.
-@return X-latched block if success, else NULL */
+/** Allocate an undo log page.
+@param[in,out]	trx	transaction
+@param[in,out]	undo	undo log
+@param[in,out]	mtr	mini-transaction that does not hold any page latch
+@return	X-latched block if success
+@retval	NULL	on failure */
 buf_block_t*
-trx_undo_add_page(
-/*==============*/
-	trx_t*		trx,		/*!< in: transaction */
-	trx_undo_t*	undo,		/*!< in: undo log memory object */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: assign undo log from
-					referred rollback segment. */
-	mtr_t*		mtr)		/*!< in: mtr which does not have
-					a latch to any undo log page;
-					the caller must have reserved
-					the rollback segment mutex */
-	MY_ATTRIBUTE((warn_unused_result));
-/********************************************************************//**
-Frees the last undo log page.
-The caller must hold the rollback segment mutex. */
+trx_undo_add_page(trx_t* trx, trx_undo_t* undo, mtr_t* mtr)
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
+
+/** Free the last undo log page. The caller must hold the rseg mutex.
+@param[in,out]	undo	undo log
+@param[in,out]	mtr	mini-transaction that does not hold any undo log page
+			or that has allocated the undo log page */
 void
-trx_undo_free_last_page_func(
-/*==========================*/
-#ifdef UNIV_DEBUG
-	const trx_t*	trx,	/*!< in: transaction */
-#endif /* UNIV_DEBUG */
-	trx_undo_t*	undo,	/*!< in/out: undo log memory copy */
-	mtr_t*		mtr);	/*!< in/out: mini-transaction which does not
-				have a latch to any undo log page or which
-				has allocated the undo log page */
-#ifdef UNIV_DEBUG
-# define trx_undo_free_last_page(trx,undo,mtr)	\
-	trx_undo_free_last_page_func(trx,undo,mtr)
-#else /* UNIV_DEBUG */
-# define trx_undo_free_last_page(trx,undo,mtr)	\
-	trx_undo_free_last_page_func(undo,mtr)
-#endif /* UNIV_DEBUG */
+trx_undo_free_last_page(trx_undo_t* undo, mtr_t* mtr)
+	MY_ATTRIBUTE((nonnull));
 
-/***********************************************************************//**
-Truncates an undo log from the end. This function is used during a rollback
-to free space from an undo log. */
+/** Truncate the tail of an undo log during rollback.
+@param[in,out]	undo	undo log
+@param[in]	limit	all undo logs after this limit will be discarded
+@param[in]	is_temp	whether this is temporary undo log */
 void
-trx_undo_truncate_end_func(
-/*=======================*/
-#ifdef UNIV_DEBUG
-	const trx_t*	trx,	/*!< in: transaction whose undo log it is */
-#endif /* UNIV_DEBUG */
-	trx_undo_t*	undo,	/*!< in/out: undo log */
-	undo_no_t	limit);	/*!< in: all undo records with undo number
-				>= this value should be truncated */
-#ifdef UNIV_DEBUG
-# define trx_undo_truncate_end(trx,undo,limit)		\
-	trx_undo_truncate_end_func(trx,undo,limit)
-#else /* UNIV_DEBUG */
-# define trx_undo_truncate_end(trx,undo,limit)		\
-	trx_undo_truncate_end_func(undo,limit)
-#endif /* UNIV_DEBUG */
+trx_undo_truncate_end(trx_undo_t* undo, undo_no_t limit, bool is_temp)
+	MY_ATTRIBUTE((nonnull));
 
 /** Truncate the head of an undo log.
 NOTE that only whole pages are freed; the header page is not
@@ -285,21 +255,19 @@ ulint
 trx_undo_lists_init(
 /*================*/
 	trx_rseg_t*	rseg);	/*!< in: rollback segment memory object */
-/**********************************************************************//**
-Assigns an undo log for a transaction. A new undo log is created or a cached
-undo log reused.
-@return DB_SUCCESS if undo log assign successful, possible error codes
-are: DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE DB_READ_ONLY
-DB_OUT_OF_MEMORY */
+/** Assign an undo log for a transaction.
+A new undo log is created or a cached undo log reused.
+@param[in,out]	trx	transaction
+@param[in]	rseg	rollback segment
+@param[out]	undo	the undo log
+@retval	DB_SUCCESS	on success
+@retval	DB_TOO_MANY_CONCURRENT_TRXS
+@retval	DB_OUT_OF_FILE_SPACE
+@retval	DB_READ_ONLY
+@retval DB_OUT_OF_MEMORY */
 dberr_t
-trx_undo_assign_undo(
-/*=================*/
-	trx_t*		trx,		/*!< in: transaction */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: assign undo log from
-					referred rollback segment. */
-	ulint		type)		/*!< in: TRX_UNDO_INSERT or
-					TRX_UNDO_UPDATE */
-	MY_ATTRIBUTE((warn_unused_result));
+trx_undo_assign_undo(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo)
+	MY_ATTRIBUTE((nonnull, warn_unused_result));
 /******************************************************************//**
 Sets the state of the undo log segment at a transaction finish.
 @return undo log segment header page, x-latched */
@@ -311,7 +279,7 @@ trx_undo_set_state_at_finish(
 
 /** Set the state of the undo log segment at a XA PREPARE or XA ROLLBACK.
 @param[in,out]	trx		transaction
-@param[in,out]	undo		insert_undo or update_undo log
+@param[in,out]	undo		undo log
 @param[in]	rollback	false=XA PREPARE, true=XA ROLLBACK
 @param[in,out]	mtr		mini-transaction
 @return undo log segment header page, x-latched */
@@ -331,24 +299,16 @@ trx_undo_update_cleanup(
 /*====================*/
 	trx_t*		trx,		/*!< in: trx owning the update
 					undo log */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: update undo log. */
 	page_t*		undo_page,	/*!< in: update undo log header page,
 					x-latched */
-	bool		update_rseg_history_len,
-					/*!< in: if true: update rseg history
-					len else skip updating it. */
-	ulint		n_added_logs,	/*!< in: number of logs added */
 	mtr_t*		mtr);		/*!< in: mtr */
 
-/** Frees an insert undo log after a transaction commit or rollback.
-Knowledge of inserts is not needed after a commit or rollback, therefore
+/** Free a temporary undo log after commit or rollback.
+The information is not needed after a commit or rollback, therefore
 the data can be discarded.
-@param[in,out]	undo_ptr	undo log to clean up
-@param[in]	noredo		whether the undo tablespace is redo logged */
+@param[in,out]	undo	undo log */
 void
-trx_undo_insert_cleanup(
-	trx_undo_ptr_t*	undo_ptr,
-	bool		noredo);
+trx_undo_commit_cleanup(trx_undo_t* undo);
 
 /********************************************************************//**
 At shutdown, frees the undo logs of a PREPARED transaction. */
@@ -381,8 +341,7 @@ trx_undo_parse_page_init(
 	const byte*	end_ptr,/*!< in: buffer end */
 	page_t*		page,	/*!< in: page or NULL */
 	mtr_t*		mtr);	/*!< in: mtr or NULL */
-/** Parse the redo log entry of an undo log page header create or reuse.
-@param[in]	type	MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE
+/** Parse the redo log entry of an undo log page header create.
 @param[in]	ptr	redo log record
 @param[in]	end_ptr	end of log buffer
 @param[in,out]	page	page frame or NULL
@@ -390,7 +349,6 @@ trx_undo_parse_page_init(
 @return end of log record or NULL */
 byte*
 trx_undo_parse_page_header(
-	mlog_id_t	type,
 	const byte*	ptr,
 	const byte*	end_ptr,
 	page_t*		page,
@@ -413,17 +371,10 @@ trx_undo_mem_free(
 	trx_undo_t*	undo);		/* in: the undo object to be freed */
 
 #endif /* !UNIV_INNOCHECKSUM */
-/* Types of an undo log segment */
-#define	TRX_UNDO_INSERT		1	/* contains undo entries for inserts */
-#define	TRX_UNDO_UPDATE		2	/* contains undo entries for updates
-					and delete markings: in short,
-					modifys (the name 'UPDATE' is a
-					historical relic) */
 /* States of an undo log segment */
 #define TRX_UNDO_ACTIVE		1	/* contains an undo log of an active
 					transaction */
 #define	TRX_UNDO_CACHED		2	/* cached for quick reuse */
-#define	TRX_UNDO_TO_FREE	3	/* insert undo segment can be freed */
 #define	TRX_UNDO_TO_PURGE	4	/* update undo segment will not be
 					reused: it can be freed in purge when
 					all undo data in it is removed */
@@ -438,8 +389,6 @@ struct trx_undo_t {
 	/*-----------------------------*/
 	ulint		id;		/*!< undo log slot number within the
 					rollback segment */
-	ulint		type;		/*!< TRX_UNDO_INSERT or
-					TRX_UNDO_UPDATE */
 	ulint		state;		/*!< state of the corresponding undo log
 					segment */
 	ibool		del_marks;	/*!< relevant only in an update undo
@@ -497,8 +446,8 @@ struct trx_undo_t {
 /*-------------------------------------------------------------*/
 /** Transaction undo log page header offsets */
 /* @{ */
-#define	TRX_UNDO_PAGE_TYPE	0	/*!< TRX_UNDO_INSERT or
-					TRX_UNDO_UPDATE */
+#define	TRX_UNDO_PAGE_TYPE	0	/*!< unused (was: TRX_UNDO_INSERT or
+					TRX_UNDO_UPDATE) */
 #define	TRX_UNDO_PAGE_START	2	/*!< Byte offset where the undo log
 					records for the LATEST transaction
 					start on this page (remember that
@@ -597,7 +546,7 @@ page of an update undo log segment. */
 #define TRX_UNDO_LOG_OLD_HDR_SIZE (34 + FLST_NODE_SIZE)
 
 /* Note: the writing of the undo log old header is coded by a log record
-MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE. The appending of an XID to the
+MLOG_UNDO_HDR_CREATE. The appending of an XID to the
 header is logged separately. In this sense, the XID is not really a member
 of the undo log header. TODO: do not append the XID to the log header if XA
 is not needed by the user. The XID wastes about 150 bytes of space in every
diff --git a/storage/innobase/log/log0log.cc b/storage/innobase/log/log0log.cc
index 1e807f8db58..91444d14039 100644
--- a/storage/innobase/log/log0log.cc
+++ b/storage/innobase/log/log0log.cc
@@ -72,7 +72,7 @@ c-function and its parameters are written to the log to
 reduce the size of the log.
 
   3a) You should not add parameters to these kind of functions
-  (e.g. trx_undo_header_create(), trx_undo_insert_header_reuse())
+  (e.g. trx_undo_header_create())
 
   3b) You should not add such functionality which either change
   working when compared with the old or are dependent on data
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index 65efaf28882..f39d4c106d4 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -2063,10 +2063,8 @@ recv_parse_or_apply_log_rec_body(
 		ptr = trx_undo_parse_discard_latest(ptr, end_ptr, page, mtr);
 		break;
 	case MLOG_UNDO_HDR_CREATE:
-	case MLOG_UNDO_HDR_REUSE:
 		ut_ad(!page || page_type == FIL_PAGE_UNDO_LOG);
-		ptr = trx_undo_parse_page_header(type, ptr, end_ptr,
-						 page, mtr);
+		ptr = trx_undo_parse_page_header(ptr, end_ptr, page, mtr);
 		break;
 	case MLOG_REC_MIN_MARK: case MLOG_COMP_REC_MIN_MARK:
 		ut_ad(!page || fil_page_type_is_index(page_type));
@@ -4657,9 +4655,6 @@ get_mlog_string(mlog_id_t type)
 	case MLOG_UNDO_HDR_DISCARD:
 		return("MLOG_UNDO_HDR_DISCARD");
 
-	case MLOG_UNDO_HDR_REUSE:
-		return("MLOG_UNDO_HDR_REUSE");
-
 	case MLOG_UNDO_HDR_CREATE:
 		return("MLOG_UNDO_HDR_CREATE");
 
diff --git a/storage/innobase/row/row0import.cc b/storage/innobase/row/row0import.cc
index 9dbb2f39c4c..827a878835b 100644
--- a/storage/innobase/row/row0import.cc
+++ b/storage/innobase/row/row0import.cc
@@ -3591,9 +3591,9 @@ row_import_for_mysql(
 
 	mutex_enter(&trx->undo_mutex);
 
-	/* IMPORT tablespace is blocked for temp-tables and so we don't
-	need to assign temporary rollback segment for this trx. */
-	err = trx_undo_assign_undo(trx, &trx->rsegs.m_redo, TRX_UNDO_UPDATE);
+	/* TODO: Do not write any undo log for the IMPORT cleanup. */
+	err = trx_undo_assign_undo(trx, trx->rsegs.m_redo.rseg,
+				   &trx->rsegs.m_redo.undo);
 
 	mutex_exit(&trx->undo_mutex);
 
@@ -3604,7 +3604,7 @@ row_import_for_mysql(
 
 		return(row_import_cleanup(prebuilt, trx, err));
 
-	} else if (trx->rsegs.m_redo.update_undo == 0) {
+	} else if (trx->rsegs.m_redo.undo == 0) {
 
 		err = DB_TOO_MANY_CONCURRENT_TRXS;
 		return(row_import_cleanup(prebuilt, trx, err));
diff --git a/storage/innobase/row/row0purge.cc b/storage/innobase/row/row0purge.cc
index c412b4348b2..c7bdd279a0e 100644
--- a/storage/innobase/row/row0purge.cc
+++ b/storage/innobase/row/row0purge.cc
@@ -412,7 +412,8 @@ row_purge_remove_sec_if_poss_leaf(
 	bool			success	= true;
 
 	log_free_check();
-
+	ut_ad(index->table == node->table);
+	ut_ad(!dict_table_is_temporary(index->table));
 	mtr_start(&mtr);
 	mtr.set_named_space(index->space);
 
@@ -436,21 +437,15 @@ row_purge_remove_sec_if_poss_leaf(
 			goto func_exit_no_pcur;
 		}
 
-		/* Change buffering is disabled for temporary tables. */
-		mode = (dict_table_is_temporary(index->table))
-			? BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED
-			: BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED
-			| BTR_DELETE;
+		mode = BTR_MODIFY_LEAF | BTR_ALREADY_S_LATCHED | BTR_DELETE;
 	} else {
 		/* For secondary indexes,
 		index->online_status==ONLINE_INDEX_COMPLETE if
 		index->is_committed(). */
 		ut_ad(!dict_index_is_online_ddl(index));
 
-		/* Change buffering is disabled for temporary tables
-		and spatial index. */
-		mode = (dict_table_is_temporary(index->table)
-			|| dict_index_is_spatial(index))
+		/* Change buffering is disabled for spatial index. */
+		mode = dict_index_is_spatial(index)
 			? BTR_MODIFY_LEAF
 			: BTR_MODIFY_LEAF | BTR_DELETE;
 	}
@@ -666,6 +661,77 @@ row_purge_del_mark(
 	return(row_purge_remove_clust_if_poss(node));
 }
 
+/** Reset DB_TRX_ID, DB_ROLL_PTR of a clustered index record
+whose old history can no longer be observed.
+@param[in,out]	node	purge node
+@param[in,out]	mtr	mini-transaction (will be started and committed) */
+static
+void
+row_purge_reset_trx_id(purge_node_t* node, mtr_t* mtr)
+{
+	ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_S));
+	/* Reset DB_TRX_ID, DB_ROLL_PTR for old records. */
+	mtr->start();
+
+	if (row_purge_reposition_pcur(BTR_MODIFY_LEAF, node, mtr)) {
+		dict_index_t*	index = dict_table_get_first_index(
+			node->table);
+		ulint	trx_id_pos = index->n_uniq ? index->n_uniq : 1;
+		rec_t*	rec = btr_pcur_get_rec(&node->pcur);
+		mem_heap_t*	heap = NULL;
+		/* Reserve enough offsets for the PRIMARY KEY and 2 columns
+		so that we can access DB_TRX_ID, DB_ROLL_PTR. */
+		ulint	offsets_[REC_OFFS_HEADER_SIZE + MAX_REF_PARTS + 2];
+		rec_offs_init(offsets_);
+		ulint*	offsets = rec_get_offsets(
+			rec, index, offsets_, trx_id_pos + 2, &heap);
+		ut_ad(heap == NULL);
+
+		ut_ad(dict_index_get_nth_field(index, trx_id_pos)
+		      ->col->mtype == DATA_SYS);
+		ut_ad(dict_index_get_nth_field(index, trx_id_pos)
+		      ->col->prtype == (DATA_TRX_ID | DATA_NOT_NULL));
+		ut_ad(dict_index_get_nth_field(index, trx_id_pos + 1)
+		      ->col->mtype == DATA_SYS);
+		ut_ad(dict_index_get_nth_field(index, trx_id_pos + 1)
+		      ->col->prtype == (DATA_ROLL_PTR | DATA_NOT_NULL));
+
+		/* Only update the record if DB_ROLL_PTR matches (the
+		record has not been modified after this transaction
+		became purgeable) */
+		if (node->roll_ptr
+		    == row_get_rec_roll_ptr(rec, index, offsets)) {
+			ut_ad(!rec_get_deleted_flag(rec,
+						    rec_offs_comp(offsets)));
+			mtr->set_named_space(index->space);
+			if (page_zip_des_t* page_zip
+			    = buf_block_get_page_zip(
+				    btr_pcur_get_block(&node->pcur))) {
+				/* FIXME: Write redo log!  If we
+				crash, it may be that the fields in
+				this ROW_FORMAT=COMPRESSED table will
+				not be reset, and row0vers will keep
+				executing the more expensive code. */
+				page_zip_write_trx_id_and_roll_ptr(
+					page_zip, rec, offsets, trx_id_pos,
+					0, 1ULL << 55);
+			} else {
+				ulint	len;
+				byte*	ptr = rec_get_nth_field(
+					rec, offsets, trx_id_pos, &len);
+				ut_ad(len == DATA_TRX_ID_LEN);
+				memset(ptr, 0, DATA_TRX_ID_LEN
+				       + DATA_ROLL_PTR_LEN);
+				ptr[DATA_TRX_ID_LEN] = 0x80; /* is_insert */
+				mlog_log_string(ptr, DATA_TRX_ID_LEN
+						+ DATA_ROLL_PTR_LEN, mtr);
+			}
+		}
+	}
+
+	mtr->commit();
+}
+
 /***********************************************************//**
 Purges an update of an existing record. Also purges an update of a delete
 marked record if that record contained an externally stored field. */
@@ -716,6 +782,8 @@ row_purge_upd_exist_or_extern_func(
 	mem_heap_free(heap);
 
 skip_secondaries:
+	mtr_t		mtr;
+	dict_index_t*	index = dict_table_get_first_index(node->table);
 	/* Free possible externally stored fields */
 	for (ulint i = 0; i < upd_get_n_fields(node->update); i++) {
 
@@ -727,12 +795,10 @@ skip_secondaries:
 			buf_block_t*	block;
 			ulint		internal_offset;
 			byte*		data_field;
-			dict_index_t*	index;
 			ibool		is_insert;
 			ulint		rseg_id;
 			ulint		page_no;
 			ulint		offset;
-			mtr_t		mtr;
 
 			/* We use the fact that new_val points to
 			undo_rec and get thus the offset of
@@ -767,7 +833,6 @@ skip_secondaries:
 			/* We have to acquire an SX-latch to the clustered
 			index tree (exclude other tree changes) */
 
-			index = dict_table_get_first_index(node->table);
 			mtr_sx_lock(dict_index_get_lock(index), &mtr);
 
 			mtr.set_named_space(index->space);
@@ -802,6 +867,8 @@ skip_secondaries:
 			mtr_commit(&mtr);
 		}
 	}
+
+	row_purge_reset_trx_id(node, &mtr);
 }
 
 #ifdef UNIV_DEBUG
@@ -827,10 +894,8 @@ row_purge_parse_undo_rec(
 {
 	dict_index_t*	clust_index;
 	byte*		ptr;
-	trx_t*		trx;
 	undo_no_t	undo_no;
 	table_id_t	table_id;
-	trx_id_t	trx_id;
 	roll_ptr_t	roll_ptr;
 	ulint		info_bits;
 	ulint		type;
@@ -844,16 +909,22 @@ row_purge_parse_undo_rec(
 
 	node->rec_type = type;
 
-	if (type == TRX_UNDO_UPD_DEL_REC && !*updated_extern) {
-
-		return(false);
+	switch (type) {
+	case TRX_UNDO_INSERT_REC:
+		break;
+	default:
+#ifdef UNIV_DEBUG
+		ut_ad(0);
+		return false;
+	case TRX_UNDO_UPD_DEL_REC:
+	case TRX_UNDO_UPD_EXIST_REC:
+	case TRX_UNDO_DEL_MARK_REC:
+#endif /* UNIV_DEBUG */
+		ptr = trx_undo_update_rec_get_sys_cols(ptr, &node->trx_id,
+						       &roll_ptr, &info_bits);
+		break;
 	}
 
-	ptr = trx_undo_update_rec_get_sys_cols(ptr, &trx_id, &roll_ptr,
-					       &info_bits);
-	node->table = NULL;
-	node->trx_id = trx_id;
-
 	/* Prevent DROP TABLE etc. from running when we are doing the purge
 	for this row */
 
@@ -867,8 +938,10 @@ try_again:
 		/* The table has been dropped: no need to do purge */
 		goto err_exit;
 	}
+	ut_ad(!dict_table_is_temporary(node->table));
 
-	if (node->table->n_v_cols && !node->table->vc_templ
+	if (type != TRX_UNDO_INSERT_REC
+	    && node->table->n_v_cols && !node->table->vc_templ
 	    && dict_table_has_indexed_v_cols(node->table)) {
 		/* Need server fully up for virtual column computation */
 		if (!mysqld_server_started) {
@@ -886,51 +959,30 @@ try_again:
 		innobase_init_vc_templ(node->table);
 	}
 
-	/* Disable purging for temp-tables as they are short-lived
-	and no point in re-organzing such short lived tables */
-	if (dict_table_is_temporary(node->table)) {
-		goto close_exit;
-	}
-
-	if (node->table->ibd_file_missing) {
-		/* We skip purge of missing .ibd files */
+	if (node->table->ibd_file_missing
+	    || !(clust_index = dict_table_get_first_index(node->table))
+	    || dict_index_is_corrupted(clust_index)) {
 
+		/* Skip the purge, because the file is missing or the
+		table is corrupted. */
 		dict_table_close(node->table, FALSE, FALSE);
-
 		node->table = NULL;
-
-		goto err_exit;
-	}
-
-	clust_index = dict_table_get_first_index(node->table);
-
-	if (clust_index == NULL
-	    || dict_index_is_corrupted(clust_index)) {
-		/* The table was corrupt in the data dictionary.
-		dict_set_corrupted() works on an index, and
-		we do not have an index to call it with. */
-close_exit:
-		dict_table_close(node->table, FALSE, FALSE);
 err_exit:
 		rw_lock_s_unlock(dict_operation_lock);
 		return(false);
 	}
 
-	if (type == TRX_UNDO_UPD_EXIST_REC
-	    && (node->cmpl_info & UPD_NODE_NO_ORD_CHANGE)
-	    && !*updated_extern) {
-
-		/* Purge requires no changes to indexes: we may return */
-		goto close_exit;
-	}
-
 	ptr = trx_undo_rec_get_row_ref(ptr, clust_index, &(node->ref),
 				       node->heap);
 
-	trx = thr_get_trx(thr);
+	if (type == TRX_UNDO_INSERT_REC) {
+		return(true);
+	}
 
-	ptr = trx_undo_update_rec_get_update(ptr, clust_index, type, trx_id,
-					     roll_ptr, info_bits, trx,
+	ptr = trx_undo_update_rec_get_update(ptr, clust_index, type,
+					     node->trx_id,
+					     roll_ptr, info_bits,
+					     thr_get_trx(thr),
 					     node->heap, &(node->update));
 
 	/* Read to the partial row the fields that occur in indexes */
@@ -980,6 +1032,8 @@ row_purge_record_func(
 		break;
 	default:
 		if (!updated_extern) {
+			mtr_t		mtr;
+			row_purge_reset_trx_id(node, &mtr);
 			break;
 		}
 		/* fall through */
diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc
index 080a8fd1335..fe62642dcca 100644
--- a/storage/innobase/row/row0trunc.cc
+++ b/storage/innobase/row/row0trunc.cc
@@ -1880,10 +1880,8 @@ row_truncate_table_for_mysql(
 		On crash (i.e. mysql restart) temporary tables are anyway not
 		accessible. */
 		mutex_enter(&trx->undo_mutex);
-
-		err = trx_undo_assign_undo(
-			trx, &trx->rsegs.m_redo, TRX_UNDO_UPDATE);
-
+		err = trx_undo_assign_undo(trx, trx->rsegs.m_redo.rseg,
+					   &trx->rsegs.m_redo.undo);
 		mutex_exit(&trx->undo_mutex);
 
 		DBUG_EXECUTE_IF("ib_err_trunc_assigning_undo_log",
diff --git a/storage/innobase/row/row0undo.cc b/storage/innobase/row/row0undo.cc
index f72e8aa14ea..e9fea3b8f10 100644
--- a/storage/innobase/row/row0undo.cc
+++ b/storage/innobase/row/row0undo.cc
@@ -278,7 +278,7 @@ row_undo(
 	if (node->state == UNDO_NODE_FETCH_NEXT) {
 
 		node->undo_rec = trx_roll_pop_top_rec_of_trx(
-			trx, trx->roll_limit, &roll_ptr, node->heap);
+			trx, &roll_ptr, node->heap);
 
 		if (!node->undo_rec) {
 			/* Rollback completed for this query thread */
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 8259aa904f9..70cee0092df 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -2416,8 +2416,7 @@ row_upd_clust_rec_by_insert_inherit_func(
 		data[BTR_EXTERN_LEN] &= ~BTR_EXTERN_OWNER_FLAG;
 		data[BTR_EXTERN_LEN] |= BTR_EXTERN_INHERITED_FLAG;
 		/* The BTR_EXTERN_INHERITED_FLAG only matters in
-		rollback of a fresh insert (insert_undo log).
-		Purge (operating on update_undo log) will always free
+		rollback of a fresh insert. Purge will always free
 		the extern fields of a delete-marked row. */
 
 		inherit = true;
diff --git a/storage/innobase/row/row0vers.cc b/storage/innobase/row/row0vers.cc
index fa10cc12eb9..37351bfe369 100644
--- a/storage/innobase/row/row0vers.cc
+++ b/storage/innobase/row/row0vers.cc
@@ -101,12 +101,25 @@ row_vers_impl_x_locked_low(
 
 	ut_ad(rec_offs_validate(rec, index, offsets));
 
+	if (ulint trx_id_offset = clust_index->trx_id_offset) {
+		trx_id = mach_read_from_6(clust_rec + trx_id_offset);
+		if (trx_id == 0) {
+			/* The transaction history was already purged. */
+			DBUG_RETURN(0);
+		}
+	}
+
 	heap = mem_heap_create(1024);
 
 	clust_offsets = rec_get_offsets(
 		clust_rec, clust_index, NULL, ULINT_UNDEFINED, &heap);
 
 	trx_id = row_get_rec_trx_id(clust_rec, clust_index, clust_offsets);
+	if (trx_id == 0) {
+		/* The transaction history was already purged. */
+		mem_heap_free(heap);
+		DBUG_RETURN(0);
+	}
 	corrupt = FALSE;
 
 	trx_t*	trx = trx_rw_is_active(trx_id, &corrupt, true);
@@ -1265,6 +1278,10 @@ row_vers_build_for_semi_consistent_read(
 			rec_trx_id = version_trx_id;
 		}
 
+		if (!version_trx_id) {
+			goto committed_version_trx;
+		}
+
 		trx_sys_mutex_enter();
 		version_trx = trx_get_rw_trx_by_id(version_trx_id);
 		/* Because version_trx is a read-write transaction,
diff --git a/storage/innobase/trx/trx0purge.cc b/storage/innobase/trx/trx0purge.cc
index b97532251d4..49748070bf3 100644
--- a/storage/innobase/trx/trx0purge.cc
+++ b/storage/innobase/trx/trx0purge.cc
@@ -315,28 +315,15 @@ void
 trx_purge_add_update_undo_to_history(
 /*=================================*/
 	trx_t*		trx,		/*!< in: transaction */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in/out: update undo log. */
 	page_t*		undo_page,	/*!< in: update undo log header page,
 					x-latched */
-	bool		update_rseg_history_len,
-					/*!< in: if true: update rseg history
-					len else skip updating it. */
-	ulint		n_added_logs,	/*!< in: number of logs added */
 	mtr_t*		mtr)		/*!< in: mtr */
 {
-	trx_undo_t*	undo;
-	trx_rseg_t*	rseg;
-	trx_rsegf_t*	rseg_header;
-	trx_ulogf_t*	undo_header;
-
-	undo = undo_ptr->update_undo;
-	rseg = undo->rseg;
-
-	rseg_header = trx_rsegf_get(
-		undo->rseg->space, undo->rseg->page_no, undo->rseg->page_size,
-		mtr);
-
-	undo_header = undo_page + undo->hdr_offset;
+	trx_undo_t*	undo		= trx->rsegs.m_redo.undo;
+	trx_rseg_t*	rseg		= undo->rseg;
+	trx_rsegf_t*	rseg_header	= trx_rsegf_get(
+		rseg->space, rseg->page_no, rseg->page_size, mtr);
+	trx_ulogf_t*	undo_header	= undo_page + undo->hdr_offset;
 
 	if (undo->state != TRX_UNDO_CACHED) {
 		ulint		hist_size;
@@ -371,11 +358,8 @@ trx_purge_add_update_undo_to_history(
 	flst_add_first(rseg_header + TRX_RSEG_HISTORY,
 		       undo_header + TRX_UNDO_HISTORY_NODE, mtr);
 
-	if (update_rseg_history_len) {
-		os_atomic_increment_ulint(
-			&trx_sys->rseg_history_len, n_added_logs);
-		srv_wake_purge_thread_if_not_active();
-	}
+	os_atomic_increment_ulint(&trx_sys->rseg_history_len, 1);
+	srv_wake_purge_thread_if_not_active();
 
 	/* Write the trx number to the undo log header */
 	mlog_write_ull(undo_header + TRX_UNDO_TRX_NO, trx->no, mtr);
@@ -1058,19 +1042,7 @@ trx_purge_initiate_truncate(
 			ulint		cached_undo_size = 0;
 
 			for (trx_undo_t* undo =
-				UT_LIST_GET_FIRST(rseg->update_undo_cached);
-			     undo != NULL && all_free;
-			     undo = UT_LIST_GET_NEXT(undo_list, undo)) {
-
-				if (limit->trx_no < undo->trx_id) {
-					all_free = false;
-				} else {
-					cached_undo_size += undo->size;
-				}
-			}
-
-			for (trx_undo_t* undo =
-				UT_LIST_GET_FIRST(rseg->insert_undo_cached);
+				     UT_LIST_GET_FIRST(rseg->undo_cached);
 			     undo != NULL && all_free;
 			     undo = UT_LIST_GET_NEXT(undo_list, undo)) {
 
diff --git a/storage/innobase/trx/trx0rec.cc b/storage/innobase/trx/trx0rec.cc
index e789a6f09a2..f05037afe0b 100644
--- a/storage/innobase/trx/trx0rec.cc
+++ b/storage/innobase/trx/trx0rec.cc
@@ -476,8 +476,8 @@ trx_undo_page_report_insert(
 	ulint		i;
 
 	ut_ad(dict_index_is_clust(index));
-	ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
-			       + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_INSERT);
+	ut_ad(*reinterpret_cast<uint16*>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE
+					 + undo_page) == 0);
 
 	first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
 				      + TRX_UNDO_PAGE_FREE);
@@ -864,7 +864,7 @@ trx_undo_page_report_modify(
 					virtual column info */
 	mtr_t*		mtr)		/*!< in: mtr */
 {
-	dict_table_t*	table;
+	dict_table_t*	table		= index->table;
 	ulint		first_free;
 	byte*		ptr;
 	const byte*	field;
@@ -874,7 +874,6 @@ trx_undo_page_report_modify(
 	byte*		type_cmpl_ptr;
 	ulint		i;
 	trx_id_t	trx_id;
-	trx_undo_ptr_t*	undo_ptr;
 	ibool		ignore_prefix = FALSE;
 	byte		ext_buf[REC_VERSION_56_MAX_INDEX_COL_LEN
 				+ BTR_EXTERN_FIELD_REF_SIZE];
@@ -882,15 +881,10 @@ trx_undo_page_report_modify(
 
 	ut_a(dict_index_is_clust(index));
 	ut_ad(rec_offs_validate(rec, index, offsets));
-	ut_ad(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
-			       + TRX_UNDO_PAGE_TYPE) == TRX_UNDO_UPDATE);
-	table = index->table;
-
-	/* If table instance is temporary then select noredo rseg as changes
-	to undo logs don't need REDO logging given that they are not
-	restored on restart as corresponding object doesn't exist on restart.*/
-	undo_ptr = dict_table_is_temporary(index->table)
-		   ? &trx->rsegs.m_noredo : &trx->rsegs.m_redo;
+	ut_ad(*reinterpret_cast<uint16*>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE
+					 + undo_page) == 0);
+	trx_undo_t*	undo = dict_table_is_temporary(table)
+		? NULL : trx->rsegs.m_redo.undo;
 
 	first_free = mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
 				      + TRX_UNDO_PAGE_FREE);
@@ -1008,8 +1002,7 @@ trx_undo_page_report_modify(
 		need to double check if there are any non-indexed columns
 		being registered in update vector in case they will be indexed
 		in new table */
-		if (dict_index_is_online_ddl(index)
-		    && index->table->n_v_cols > 0) {
+		if (dict_index_is_online_ddl(index) && table->n_v_cols > 0) {
 			for (i = 0; i < upd_get_n_fields(update); i++) {
 				upd_field_t*	fld = upd_get_nth_field(
 					update, i);
@@ -1115,7 +1108,9 @@ trx_undo_page_report_modify(
 				/* Notify purge that it eventually has to
 				free the old externally stored field */
 
-				undo_ptr->update_undo->del_marks = TRUE;
+				if (undo) {
+					undo->del_marks = TRUE;
+				}
 
 				*type_cmpl_ptr |= TRX_UNDO_UPD_EXTERN;
 			} else {
@@ -1184,7 +1179,9 @@ trx_undo_page_report_modify(
 		double		mbr[SPDIMS * 2];
 		mem_heap_t*	row_heap = NULL;
 
-		undo_ptr->update_undo->del_marks = TRUE;
+		if (undo) {
+			undo->del_marks = TRUE;
+		}
 
 		if (trx_undo_left(undo_page, ptr) < 5) {
 
@@ -1475,7 +1472,7 @@ trx_undo_update_rec_get_update(
 
 	buf = static_cast<byte*>(mem_heap_alloc(heap, DATA_TRX_ID_LEN));
 
-	trx_write_trx_id(buf, trx_id);
+	mach_write_to_6(buf, trx_id);
 
 	upd_field_set_field_no(upd_field,
 			       dict_index_get_sys_col_pos(index, DATA_TRX_ID),
@@ -1858,18 +1855,19 @@ trx_undo_report_row_operation(
 					flag was specified */
 {
 	trx_t*		trx;
-	trx_undo_t*	undo;
 	ulint		page_no;
 	buf_block_t*	undo_block;
-	trx_undo_ptr_t*	undo_ptr;
 	mtr_t		mtr;
-	dberr_t		err		= DB_SUCCESS;
 #ifdef UNIV_DEBUG
 	int		loop_count	= 0;
 #endif /* UNIV_DEBUG */
 
 	ut_a(dict_index_is_clust(index));
 	ut_ad(!rec || rec_offs_validate(rec, index, offsets));
+	ut_ad(!srv_read_only_mode);
+	ut_ad(op_type == TRX_UNDO_INSERT_OP || op_type == TRX_UNDO_MODIFY_OP);
+	ut_ad((op_type != TRX_UNDO_INSERT_OP)
+	      || (clust_entry && !update && !rec));
 
 	if (flags & BTR_NO_UNDO_LOG_FLAG) {
 
@@ -1878,87 +1876,42 @@ trx_undo_report_row_operation(
 		return(DB_SUCCESS);
 	}
 
-	ut_ad(thr);
-	ut_ad(!srv_read_only_mode);
-	ut_ad((op_type != TRX_UNDO_INSERT_OP)
-	      || (clust_entry && !update && !rec));
-
 	trx = thr_get_trx(thr);
 
-	bool	is_temp_table = dict_table_is_temporary(index->table);
-
-	/* Temporary tables do not go into INFORMATION_SCHEMA.TABLES,
-	so do not bother adding it to the list of modified tables by
-	the transaction - this list is only used for maintaining
-	INFORMATION_SCHEMA.TABLES.UPDATE_TIME. */
-	if (!is_temp_table) {
-		trx->mod_tables.insert(index->table);
-	}
-
-	/* If trx is read-only then only temp-tables can be written.
-	If trx is read-write and involves temp-table only then we
-	assign temporary rseg. */
-	if (trx->read_only || is_temp_table) {
+	mtr.start();
+	trx_undo_t**	pundo;
+	trx_rseg_t*	rseg;
+	const bool	is_temp	= dict_table_is_temporary(index->table);
 
-		ut_ad(!srv_read_only_mode || is_temp_table);
+	if (is_temp) {
+		mtr.set_log_mode(MTR_LOG_NO_REDO);
 
-		/* MySQL should block writes to non-temporary tables. */
-		ut_a(is_temp_table);
+		rseg = trx->rsegs.m_noredo.rseg;
 
-		if (trx->rsegs.m_noredo.rseg == 0) {
+		if (!rseg) {
 			trx_assign_rseg(trx);
+			rseg = trx->rsegs.m_noredo.rseg;
 		}
-	}
-
-	/* If object is temporary, disable REDO logging that is done to track
-	changes done to UNDO logs. This is feasible given that temporary tables
-	are not restored on restart. */
-	mtr_start(&mtr);
-	dict_disable_redo_if_temporary(index->table, &mtr);
-	mutex_enter(&trx->undo_mutex);
-
-	/* If object is temp-table then select noredo rseg as changes
-	to undo logs don't need REDO logging given that they are not
-	restored on restart as corresponding object doesn't exist on restart.*/
-	undo_ptr = is_temp_table ? &trx->rsegs.m_noredo : &trx->rsegs.m_redo;
-
-	switch (op_type) {
-	case TRX_UNDO_INSERT_OP:
-		undo = undo_ptr->insert_undo;
-
-		if (undo == NULL) {
-
-			err = trx_undo_assign_undo(
-				trx, undo_ptr, TRX_UNDO_INSERT);
-			undo = undo_ptr->insert_undo;
-
-			if (undo == NULL) {
-				/* Did not succeed */
-				ut_ad(err != DB_SUCCESS);
-				goto err_exit;
-			}
-
-			ut_ad(err == DB_SUCCESS);
-		}
-		break;
-	default:
-		ut_ad(op_type == TRX_UNDO_MODIFY_OP);
 
-		undo = undo_ptr->update_undo;
+		pundo = &trx->rsegs.m_noredo.undo;
+	} else {
+		ut_ad(!trx->read_only);
+		/* Keep INFORMATION_SCHEMA.TABLES.UPDATE_TIME
+		up-to-date for persistent tables. Temporary tables are
+		not listed there. */
+		trx->mod_tables.insert(index->table);
 
-		if (undo == NULL) {
-			err = trx_undo_assign_undo(
-				trx, undo_ptr, TRX_UNDO_UPDATE);
-			undo = undo_ptr->update_undo;
+		pundo = &trx->rsegs.m_redo.undo;
+		rseg = trx->rsegs.m_redo.rseg;
+	}
 
-			if (undo == NULL) {
-				/* Did not succeed */
-				ut_ad(err != DB_SUCCESS);
-				goto err_exit;
-			}
-		}
+	mutex_enter(&trx->undo_mutex);
+	dberr_t	err = *pundo ? DB_SUCCESS : trx_undo_assign_undo(trx, rseg, pundo);
+	trx_undo_t*	undo = *pundo;
 
-		ut_ad(err == DB_SUCCESS);
+	ut_ad((err == DB_SUCCESS) == (undo != NULL));
+	if (undo == NULL) {
+		goto err_exit;
 	}
 
 	page_no = undo->last_page_no;
@@ -2012,13 +1965,14 @@ trx_undo_report_row_operation(
 				latches, such as SYNC_FSP and SYNC_FSP_PAGE. */
 
 				mtr_commit(&mtr);
-				mtr_start(&mtr);
-				dict_disable_redo_if_temporary(
-					index->table, &mtr);
+				mtr.start(trx);
+				if (is_temp) {
+					mtr.set_log_mode(MTR_LOG_NO_REDO);
+				}
 
-				mutex_enter(&undo_ptr->rseg->mutex);
-				trx_undo_free_last_page(trx, undo, &mtr);
-				mutex_exit(&undo_ptr->rseg->mutex);
+				mutex_enter(&rseg->mutex);
+				trx_undo_free_last_page(undo, &mtr);
+				mutex_exit(&rseg->mutex);
 
 				err = DB_UNDO_RECORD_TOO_BIG;
 				goto err_exit;
@@ -2037,13 +1991,13 @@ trx_undo_report_row_operation(
 			undo->guess_block = undo_block;
 
 			trx->undo_no++;
-			trx->undo_rseg_space = undo_ptr->rseg->space;
+			trx->undo_rseg_space = rseg->space;
 
 			mutex_exit(&trx->undo_mutex);
 
 			*roll_ptr = trx_undo_build_roll_ptr(
 				op_type == TRX_UNDO_INSERT_OP,
-				undo_ptr->rseg->id, page_no, offset);
+				rseg->id, page_no, offset);
 			return(DB_SUCCESS);
 		}
 
@@ -2052,17 +2006,13 @@ trx_undo_report_row_operation(
 		/* We have to extend the undo log by one page */
 
 		ut_ad(++loop_count < 2);
-		mtr_start(&mtr);
-		dict_disable_redo_if_temporary(index->table, &mtr);
+		mtr.start(trx);
 
-		/* When we add a page to an undo log, this is analogous to
-		a pessimistic insert in a B-tree, and we must reserve the
-		counterpart of the tree latch, which is the rseg mutex. */
-
-		mutex_enter(&undo_ptr->rseg->mutex);
-		undo_block = trx_undo_add_page(trx, undo, undo_ptr, &mtr);
-		mutex_exit(&undo_ptr->rseg->mutex);
+		if (is_temp) {
+			mtr.set_log_mode(MTR_LOG_NO_REDO);
+		}
 
+		undo_block = trx_undo_add_page(trx, undo, &mtr);
 		page_no = undo->last_page_no;
 
 		DBUG_EXECUTE_IF("ib_err_ins_undo_page_add_failure",
@@ -2075,10 +2025,8 @@ trx_undo_report_row_operation(
 		" log pages. Please add new data file to the tablespace or"
 		" check if filesystem is full or enable auto-extension for"
 		" the tablespace",
-		((undo->space == srv_sys_space.space_id())
-		? "system" :
-		  ((fsp_is_system_temporary(undo->space))
-		   ? "temporary" : "undo")));
+		undo->space == TRX_SYS_SPACE
+		? "system" : is_temp ? "temporary" : "undo");
 
 	/* Did not succeed: out of space */
 	err = DB_OUT_OF_FILE_SPACE;
diff --git a/storage/innobase/trx/trx0roll.cc b/storage/innobase/trx/trx0roll.cc
index 4044bd44b63..1e1a35a2eb1 100644
--- a/storage/innobase/trx/trx0roll.cc
+++ b/storage/innobase/trx/trx0roll.cc
@@ -213,27 +213,17 @@ trx_rollback_low(
 
 	case TRX_STATE_PREPARED:
 		ut_ad(!trx_is_autocommit_non_locking(trx));
-		if (trx->rsegs.m_redo.rseg != NULL
-		    && trx_is_redo_rseg_updated(trx)) {
+		if (trx_undo_t* undo = trx->rsegs.m_redo.undo) {
 			/* Change the undo log state back from
 			TRX_UNDO_PREPARED to TRX_UNDO_ACTIVE
 			so that if the system gets killed,
 			recovery will perform the rollback. */
-			trx_undo_ptr_t*	undo_ptr = &trx->rsegs.m_redo;
+			ut_ad(undo->rseg == trx->rsegs.m_redo.rseg);
 			mtr_t		mtr;
 			mtr.start();
-			mutex_enter(&trx->rsegs.m_redo.rseg->mutex);
-			if (undo_ptr->insert_undo != NULL) {
-				trx_undo_set_state_at_prepare(
-					trx, undo_ptr->insert_undo,
-					true, &mtr);
-			}
-			if (undo_ptr->update_undo != NULL) {
-				trx_undo_set_state_at_prepare(
-					trx, undo_ptr->update_undo,
-					true, &mtr);
-			}
-			mutex_exit(&trx->rsegs.m_redo.rseg->mutex);
+			mutex_enter(&undo->rseg->mutex);
+			trx_undo_set_state_at_prepare(trx, undo, true, &mtr);
+			mutex_exit(&undo->rseg->mutex);
 			/* Persist the XA ROLLBACK, so that crash
 			recovery will replay the rollback in case
 			the redo log gets applied past this point. */
@@ -874,27 +864,30 @@ DECLARE_THREAD(trx_rollback_or_clean_all_recovered)(
 	OS_THREAD_DUMMY_RETURN;
 }
 
-/***********************************************************************//**
-Tries truncate the undo logs. */
+/** Try to truncate the undo logs.
+@param[in,out]	trx	transaction */
 static
 void
-trx_roll_try_truncate(
-/*==================*/
-	trx_t*		trx,		/*!< in/out: transaction */
-	trx_undo_ptr_t*	undo_ptr)	/*!< in: rollback segment to look
-					for next undo log record. */
+trx_roll_try_truncate(trx_t* trx)
 {
 	ut_ad(mutex_own(&trx->undo_mutex));
-	ut_ad(mutex_own(&undo_ptr->rseg->mutex));
 
 	trx->pages_undone = 0;
 
-	if (undo_ptr->insert_undo) {
-		trx_undo_truncate_end(trx, undo_ptr->insert_undo, trx->undo_no);
+	undo_no_t	undo_no		= trx->undo_no;
+
+	if (trx_undo_t*	undo = trx->rsegs.m_redo.undo) {
+		ut_ad(undo->rseg == trx->rsegs.m_redo.rseg);
+		mutex_enter(&undo->rseg->mutex);
+		trx_undo_truncate_end(undo, undo_no, false);
+		mutex_exit(&undo->rseg->mutex);
 	}
 
-	if (undo_ptr->update_undo) {
-		trx_undo_truncate_end(trx, undo_ptr->update_undo, trx->undo_no);
+	if (trx_undo_t* undo = trx->rsegs.m_noredo.undo) {
+		ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg);
+		mutex_enter(&undo->rseg->mutex);
+		trx_undo_truncate_end(undo, undo_no, true);
+		mutex_exit(&undo->rseg->mutex);
 	}
 }
 
@@ -941,75 +934,56 @@ trx_roll_pop_top_rec(
 	return(undo_page + offset);
 }
 
-
-/********************************************************************//**
-Pops the topmost record when the two undo logs of a transaction are seen
-as a single stack of records ordered by their undo numbers.
-@return undo log record copied to heap, NULL if none left, or if the
-undo number of the top record would be less than the limit */
+/** Get the last undo log record of a transaction (for rollback).
+@param[in,out]	trx		transaction
+@param[out]	roll_ptr	DB_ROLL_PTR to the undo record
+@param[in,out]	heap		memory heap for allocation
+@return	undo log record copied to heap
+@retval	NULL if none left or the roll_limit (savepoint) was reached */
 trx_undo_rec_t*
-trx_roll_pop_top_rec_of_trx_low(
-/*============================*/
-	trx_t*		trx,		/*!< in/out: transaction */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: rollback segment to look
-					for next undo log record. */
-	undo_no_t	limit,		/*!< in: least undo number we need */
-	roll_ptr_t*	roll_ptr,	/*!< out: roll pointer to undo record */
-	mem_heap_t*	heap)		/*!< in/out: memory heap where copied */
+trx_roll_pop_top_rec_of_trx(trx_t* trx, roll_ptr_t* roll_ptr, mem_heap_t* heap)
 {
-	trx_undo_t*	undo;
-	trx_undo_t*	ins_undo;
-	trx_undo_t*	upd_undo;
-	trx_undo_rec_t*	undo_rec;
-	trx_undo_rec_t*	undo_rec_copy;
-	undo_no_t	undo_no;
-	ibool		is_insert;
-	trx_rseg_t*	rseg;
-	mtr_t		mtr;
-
-	rseg = undo_ptr->rseg;
-
 	mutex_enter(&trx->undo_mutex);
 
 	if (trx->pages_undone >= TRX_ROLL_TRUNC_THRESHOLD) {
-		mutex_enter(&rseg->mutex);
-
-		trx_roll_try_truncate(trx, undo_ptr);
-
-		mutex_exit(&rseg->mutex);
+		trx_roll_try_truncate(trx);
 	}
 
-	ins_undo = undo_ptr->insert_undo;
-	upd_undo = undo_ptr->update_undo;
+	trx_undo_t*	undo	= trx->rsegs.m_redo.undo;
+	trx_undo_t*	temp	= trx->rsegs.m_noredo.undo;
+	const undo_no_t	limit	= trx->roll_limit;
 
-	if (!ins_undo || ins_undo->empty) {
-		undo = upd_undo;
-	} else if (!upd_undo || upd_undo->empty) {
-		undo = ins_undo;
-	} else if (upd_undo->top_undo_no > ins_undo->top_undo_no) {
-		undo = upd_undo;
-	} else {
-		undo = ins_undo;
-	}
+	ut_ad(!undo || !temp || !undo->top_undo_no
+	      || undo->top_undo_no != temp->top_undo_no);
 
-	if (!undo || undo->empty || limit > undo->top_undo_no) {
-		mutex_enter(&rseg->mutex);
-		trx_roll_try_truncate(trx, undo_ptr);
-		mutex_exit(&rseg->mutex);
+	if (undo && !undo->empty && limit <= undo->top_undo_no) {
+	} else if (temp && !temp->empty && limit <= temp->top_undo_no) {
+		undo = temp;
+	} else {
+		trx_roll_try_truncate(trx);
+		/* Mark any ROLLBACK TO SAVEPOINT completed, so that
+		if the transaction object is committed and reused
+		later, we will default to a full ROLLBACK. */
+		trx->roll_limit = 0;
+		ut_d(trx->in_rollback = false);
 		mutex_exit(&trx->undo_mutex);
 		return(NULL);
 	}
 
-	is_insert = (undo == ins_undo);
+	ut_ad(!undo->empty);
+	ut_ad(limit <= undo->top_undo_no);
 
 	*roll_ptr = trx_undo_build_roll_ptr(
-		is_insert, undo->rseg->id, undo->top_page_no, undo->top_offset);
-
-	mtr_start(&mtr);
+		false, undo->rseg->id, undo->top_page_no, undo->top_offset);
 
-	undo_rec = trx_roll_pop_top_rec(trx, undo, &mtr);
+	mtr_t	mtr;
+	mtr.start();
 
-	undo_no = trx_undo_rec_get_undo_no(undo_rec);
+	trx_undo_rec_t*	undo_rec = trx_roll_pop_top_rec(trx, undo, &mtr);
+	const undo_no_t	undo_no = trx_undo_rec_get_undo_no(undo_rec);
+	if (trx_undo_rec_get_type(undo_rec) == TRX_UNDO_INSERT_REC) {
+		*roll_ptr |= 1ULL << 55; /* is_insert */
+	}
 
 	ut_ad(trx_roll_check_undo_rec_ordering(
 		undo_no, undo->rseg->space, trx));
@@ -1037,43 +1011,14 @@ trx_roll_pop_top_rec_of_trx_low(
 
 	trx->undo_no = undo_no;
 	trx->undo_rseg_space = undo->rseg->space;
-
-	undo_rec_copy = trx_undo_rec_copy(undo_rec, heap);
-
 	mutex_exit(&trx->undo_mutex);
 
-	mtr_commit(&mtr);
+	trx_undo_rec_t*	undo_rec_copy = trx_undo_rec_copy(undo_rec, heap);
+	mtr.commit();
 
 	return(undo_rec_copy);
 }
 
-/********************************************************************//**
-Get next undo log record from redo and noredo rollback segments.
-@return undo log record copied to heap, NULL if none left, or if the
-undo number of the top record would be less than the limit */
-trx_undo_rec_t*
-trx_roll_pop_top_rec_of_trx(
-/*========================*/
-	trx_t*		trx,		/*!< in: transaction */
-	undo_no_t	limit,		/*!< in: least undo number we need */
-	roll_ptr_t*	roll_ptr,	/*!< out: roll pointer to undo record */
-	mem_heap_t*	heap)		/*!< in: memory heap where copied */
-{
-	trx_undo_rec_t* undo_rec = 0;
-
-	if (trx_is_redo_rseg_updated(trx)) {
-		undo_rec = trx_roll_pop_top_rec_of_trx_low(
-			trx, &trx->rsegs.m_redo, limit, roll_ptr, heap);
-	}
-
-	if (undo_rec == 0 && trx_is_noredo_rseg_updated(trx)) {
-		undo_rec = trx_roll_pop_top_rec_of_trx_low(
-			trx, &trx->rsegs.m_noredo, limit, roll_ptr, heap);
-	}
-
-	return(undo_rec);
-}
-
 /****************************************************************//**
 Builds an undo 'query' graph for a transaction. The actual rollback is
 performed by executing this query graph like a query subprocedure call.
diff --git a/storage/innobase/trx/trx0rseg.cc b/storage/innobase/trx/trx0rseg.cc
index d5520b783b1..2337a80c232 100644
--- a/storage/innobase/trx/trx0rseg.cc
+++ b/storage/innobase/trx/trx0rseg.cc
@@ -131,29 +131,15 @@ trx_rseg_mem_free(
 	mutex_free(&rseg->mutex);
 
 	/* There can't be any active transactions. */
-	ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0);
-	ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0);
+	ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0);
 
-	for (undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
+	for (undo = UT_LIST_GET_FIRST(rseg->undo_cached);
 	     undo != NULL;
 	     undo = next_undo) {
 
 		next_undo = UT_LIST_GET_NEXT(undo_list, undo);
 
-		UT_LIST_REMOVE(rseg->update_undo_cached, undo);
-
-		MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
-
-		trx_undo_mem_free(undo);
-	}
-
-	for (undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
-	     undo != NULL;
-	     undo = next_undo) {
-
-		next_undo = UT_LIST_GET_NEXT(undo_list, undo);
-
-		UT_LIST_REMOVE(rseg->insert_undo_cached, undo);
+		UT_LIST_REMOVE(rseg->undo_cached, undo);
 
 		MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
 
@@ -211,10 +197,8 @@ trx_rseg_mem_create(
 		mutex_create(LATCH_ID_REDO_RSEG, &rseg->mutex);
 	}
 
-	UT_LIST_INIT(rseg->update_undo_list, &trx_undo_t::undo_list);
-	UT_LIST_INIT(rseg->update_undo_cached, &trx_undo_t::undo_list);
-	UT_LIST_INIT(rseg->insert_undo_list, &trx_undo_t::undo_list);
-	UT_LIST_INIT(rseg->insert_undo_cached, &trx_undo_t::undo_list);
+	UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list);
+	UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list);
 
 	*((trx_rseg_t**) rseg_array + rseg->id) = rseg;
 
diff --git a/storage/innobase/trx/trx0sys.cc b/storage/innobase/trx/trx0sys.cc
index bb57aab4031..7cd18750945 100644
--- a/storage/innobase/trx/trx0sys.cc
+++ b/storage/innobase/trx/trx0sys.cc
@@ -1290,13 +1290,9 @@ trx_sys_any_active_transactions(void)
 				Pretend that it is in XA PREPARE
 				state so that shutdown will work. */
 				trx_undo_fake_prepared(
-					trx, trx->rsegs.m_redo.insert_undo);
+					trx, trx->rsegs.m_redo.undo);
 				trx_undo_fake_prepared(
-					trx, trx->rsegs.m_redo.update_undo);
-				trx_undo_fake_prepared(
-					trx, trx->rsegs.m_noredo.insert_undo);
-				trx_undo_fake_prepared(
-					trx, trx->rsegs.m_noredo.update_undo);
+					trx, trx->rsegs.m_noredo.undo);
 				trx->state = TRX_STATE_PREPARED;
 				trx_sys->n_prepared_trx++;
 				trx_sys->n_prepared_recovered_trx++;
diff --git a/storage/innobase/trx/trx0trx.cc b/storage/innobase/trx/trx0trx.cc
index 7f89df7094a..c0fb7606887 100644
--- a/storage/innobase/trx/trx0trx.cc
+++ b/storage/innobase/trx/trx0trx.cc
@@ -713,8 +713,6 @@ void
 trx_resurrect_table_locks(
 /*======================*/
 	trx_t*			trx,	/*!< in/out: transaction */
-	const trx_undo_ptr_t*	undo_ptr,
-					/*!< in: pointer to undo segment. */
 	const trx_undo_t*	undo)	/*!< in: undo log */
 {
 	mtr_t			mtr;
@@ -722,8 +720,6 @@ trx_resurrect_table_locks(
 	trx_undo_rec_t*		undo_rec;
 	table_id_set		tables;
 
-	ut_ad(undo == undo_ptr->insert_undo || undo == undo_ptr->update_undo);
-
 	if (trx_state_eq(trx, TRX_STATE_COMMITTED_IN_MEMORY) || undo->empty) {
 
 		return;
@@ -785,27 +781,22 @@ trx_resurrect_table_locks(
 
 			DBUG_PRINT("ib_trx",
 				   ("resurrect" TRX_ID_FMT
-				    "  table '%s' IX lock from %s undo",
+				    "  table '%s' IX lock",
 				    trx_get_id_for_print(trx),
-				    table->name.m_name,
-				    undo == undo_ptr->insert_undo
-				    ? "insert" : "update"));
+				    table->name.m_name));
 
 			dict_table_close(table, FALSE, FALSE);
 		}
 	}
 }
 
-/****************************************************************//**
-Resurrect the transactions that were doing inserts the time of the
-crash, they need to be undone.
-@return trx_t instance */
+/** Resurrect the transactions that exited at the time of the
+previous crash or shutdown.
+@param[in,out]	undo	undo log
+@return transaction instance */
 static
 trx_t*
-trx_resurrect_insert(
-/*=================*/
-	trx_undo_t*	undo,		/*!< in: entry to UNDO */
-	trx_rseg_t*	rseg)		/*!< in: rollback segment */
+trx_resurrect(trx_undo_t* undo)
 {
 	trx_t*		trx;
 
@@ -814,71 +805,45 @@ trx_resurrect_insert(
 	ut_d(trx->start_file = __FILE__);
 	ut_d(trx->start_line = __LINE__);
 
-	trx->rsegs.m_redo.rseg = rseg;
-	/* For transactions with active data will not have rseg size = 1
-	or will not qualify for purge limit criteria. So it is safe to increment
-	this trx_ref_count w/o mutex protection. */
-	++trx->rsegs.m_redo.rseg->trx_ref_count;
+	trx->rsegs.m_redo.rseg = undo->rseg;
+	trx->rsegs.m_redo.undo = undo;
+	/* It is safe to skip the mutex protection, because purge is
+	not running and transactions cannot be created yet. */
+	++undo->rseg->trx_ref_count;
 	*trx->xid = undo->xid;
 	trx->id = undo->trx_id;
-	trx->rsegs.m_redo.insert_undo = undo;
 	trx->is_recovered = true;
 
-	/* This is single-threaded startup code, we do not need the
-	protection of trx->mutex or trx_sys->mutex here. */
-
-	if (undo->state != TRX_UNDO_ACTIVE) {
+	/* We assign a dummy value for the commit number; this should
+	have no relevance since purge is not interested in committed
+	transaction numbers, unless they are in the history list, in
+	which case it looks the number from the disk based undo log
+	structure */
+	trx->no = trx->id;
 
+	switch (undo->state) {
+	case TRX_UNDO_PREPARED:
 		/* Prepared transactions are left in the prepared state
 		waiting for a commit or abort decision from MySQL */
 
-		if (undo->state == TRX_UNDO_PREPARED) {
-
-			ib::info() << "Transaction "
-				<< trx_get_id_for_print(trx)
-				<< " was in the XA prepared state.";
-
-			if (srv_force_recovery == 0) {
-
-				trx->state = TRX_STATE_PREPARED;
-				++trx_sys->n_prepared_trx;
-				++trx_sys->n_prepared_recovered_trx;
-			} else {
-
-				ib::info() << "Since innodb_force_recovery"
-					" > 0, we will force a rollback.";
-
-				trx->state = TRX_STATE_ACTIVE;
-			}
-		} else {
-			trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
-		}
-
-		/* We give a dummy value for the trx no; this should have no
-		relevance since purge is not interested in committed
-		transaction numbers, unless they are in the history
-		list, in which case it looks the number from the disk based
-		undo log structure */
+		ib::info() << "Transaction " << ib::hex(trx->id)
+			<< " was in the XA prepared state.";
 
-		trx->no = trx->id;
+		trx->state = TRX_STATE_PREPARED;
+		++trx_sys->n_prepared_trx;
+		++trx_sys->n_prepared_recovered_trx;
+		break;
+	default:
+		trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
+		break;
 
-	} else {
+	case TRX_UNDO_ACTIVE:
 		trx->state = TRX_STATE_ACTIVE;
-
 		/* A running transaction always has the number
 		field inited to TRX_ID_MAX */
-
 		trx->no = TRX_ID_MAX;
 	}
 
-	/* trx_start_low() is not called with resurrect, so need to initialize
-	start time here.*/
-	if (trx->state == TRX_STATE_ACTIVE
-	    || trx->state == TRX_STATE_PREPARED) {
-
-		trx->start_time = ut_time();
-	}
-
 	if (undo->dict_operation) {
 		trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
 		trx->table_id = undo->table_id;
@@ -893,105 +858,6 @@ trx_resurrect_insert(
 }
 
 /****************************************************************//**
-Prepared transactions are left in the prepared state waiting for a
-commit or abort decision from MySQL */
-static
-void
-trx_resurrect_update_in_prepared_state(
-/*===================================*/
-	trx_t*			trx,	/*!< in,out: transaction */
-	const trx_undo_t*	undo)	/*!< in: update UNDO record */
-{
-	/* This is single-threaded startup code, we do not need the
-	protection of trx->mutex or trx_sys->mutex here. */
-
-	if (undo->state == TRX_UNDO_PREPARED) {
-		ib::info() << "Transaction " << trx_get_id_for_print(trx)
-			<< " was in the XA prepared state.";
-
-		if (srv_force_recovery == 0) {
-
-			ut_ad(trx->state != TRX_STATE_FORCED_ROLLBACK);
-
-			if (trx_state_eq(trx, TRX_STATE_NOT_STARTED)) {
-				++trx_sys->n_prepared_trx;
-				++trx_sys->n_prepared_recovered_trx;
-			} else {
-				ut_ad(trx_state_eq(trx, TRX_STATE_PREPARED));
-			}
-
-			trx->state = TRX_STATE_PREPARED;
-		} else {
-			ib::info() << "Since innodb_force_recovery > 0, we"
-				" will rollback it anyway.";
-
-			trx->state = TRX_STATE_ACTIVE;
-		}
-	} else {
-		trx->state = TRX_STATE_COMMITTED_IN_MEMORY;
-	}
-}
-
-/****************************************************************//**
-Resurrect the transactions that were doing updates the time of the
-crash, they need to be undone. */
-static
-void
-trx_resurrect_update(
-/*=================*/
-	trx_t*		trx,	/*!< in/out: transaction */
-	trx_undo_t*	undo,	/*!< in/out: update UNDO record */
-	trx_rseg_t*	rseg)	/*!< in/out: rollback segment */
-{
-	trx->rsegs.m_redo.rseg = rseg;
-	/* For transactions with active data will not have rseg size = 1
-	or will not qualify for purge limit criteria. So it is safe to increment
-	this trx_ref_count w/o mutex protection. */
-	++trx->rsegs.m_redo.rseg->trx_ref_count;
-	*trx->xid = undo->xid;
-	trx->id = undo->trx_id;
-	trx->rsegs.m_redo.update_undo = undo;
-	trx->is_recovered = true;
-
-	/* This is single-threaded startup code, we do not need the
-	protection of trx->mutex or trx_sys->mutex here. */
-
-	if (undo->state != TRX_UNDO_ACTIVE) {
-		trx_resurrect_update_in_prepared_state(trx, undo);
-
-		/* We give a dummy value for the trx number */
-
-		trx->no = trx->id;
-
-	} else {
-		trx->state = TRX_STATE_ACTIVE;
-
-		/* A running transaction always has the number field inited to
-		TRX_ID_MAX */
-
-		trx->no = TRX_ID_MAX;
-	}
-
-	/* trx_start_low() is not called with resurrect, so need to initialize
-	start time here.*/
-	if (trx->state == TRX_STATE_ACTIVE
-	    || trx->state == TRX_STATE_PREPARED) {
-		trx->start_time = ut_time();
-	}
-
-	if (undo->dict_operation) {
-		trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
-		trx->table_id = undo->table_id;
-	}
-
-	if (!undo->empty && undo->top_undo_no >= trx->undo_no) {
-
-		trx->undo_no = undo->top_undo_no + 1;
-		trx->undo_rseg_space = undo->rseg->space;
-	}
-}
-
-/****************************************************************//**
 Creates trx objects for transactions and initializes the trx list of
 trx_sys at database start. Rollback segment and undo log lists must
 already exist when this function is called, because the lists of
@@ -1008,8 +874,8 @@ trx_lists_init_at_db_start(void)
 	not need to look at pending_purge_rseg_array for rollbacking
 	transactions. */
 
+	ib_time_t start_time = ut_time();
 	for (ulint i = 0; i < TRX_SYS_N_RSEGS; ++i) {
-		trx_undo_t*	undo;
 		trx_rseg_t*	rseg = trx_sys->rseg_array[i];
 
 		/* At this stage non-redo rseg slots are all NULL as they are
@@ -1019,45 +885,16 @@ trx_lists_init_at_db_start(void)
 		}
 
 		/* Resurrect transactions that were doing inserts. */
-		for (undo = UT_LIST_GET_FIRST(rseg->insert_undo_list);
+		for (trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_list);
 		     undo != NULL;
 		     undo = UT_LIST_GET_NEXT(undo_list, undo)) {
+			ut_ad(undo->rseg == rseg);
 
-			trx_t*	trx;
-
-			trx = trx_resurrect_insert(undo, rseg);
-
+			trx_t*	trx = trx_resurrect(undo);
+			trx->start_time = start_time;
 			trx_sys_rw_trx_add(trx);
 
-			trx_resurrect_table_locks(
-				trx, &trx->rsegs.m_redo, undo);
-		}
-
-		/* Ressurrect transactions that were doing updates. */
-		for (undo = UT_LIST_GET_FIRST(rseg->update_undo_list);
-		     undo != NULL;
-		     undo = UT_LIST_GET_NEXT(undo_list, undo)) {
-
-			/* Check the trx_sys->rw_trx_set first. */
-			trx_sys_mutex_enter();
-
-			trx_t*	trx = trx_get_rw_trx_by_id(undo->trx_id);
-
-			trx_sys_mutex_exit();
-
-			if (trx == NULL) {
-				trx = trx_allocate_for_background();
-
-				ut_d(trx->start_file = __FILE__);
-				ut_d(trx->start_line = __LINE__);
-			}
-
-			trx_resurrect_update(trx, undo, rseg);
-
-			trx_sys_rw_trx_add(trx);
-
-			trx_resurrect_table_locks(
-				trx, &trx->rsegs.m_redo, undo);
+			trx_resurrect_table_locks(trx, undo);
 		}
 	}
 
@@ -1467,65 +1304,29 @@ trx_start_low(
 	MONITOR_INC(MONITOR_TRX_ACTIVE);
 }
 
-/****************************************************************//**
-Set the transaction serialisation number.
-@return true if the transaction number was added to the serialisation_list. */
+/** Set the serialisation number for a persistent committed transaction.
+@param[in,out]	trx	committed transaction with persistent changes
+@param[in,out]	rseg	rollback segment for undo, or NULL */
 static
-bool
-trx_serialisation_number_get(
-/*=========================*/
-	trx_t*		trx,			/*!< in/out: transaction */
-	trx_undo_ptr_t*	redo_rseg_undo_ptr,	/*!< in/out: Set trx
-						serialisation number in
-						referred undo rseg. */
-	trx_undo_ptr_t*	noredo_rseg_undo_ptr)	/*!< in/out: Set trx
-						serialisation number in
-						referred undo rseg. */
+void
+trx_serialise(trx_t* trx, trx_rseg_t* rseg)
 {
-	bool		added_trx_no;
-	trx_rseg_t*	redo_rseg = 0;
-	trx_rseg_t*	noredo_rseg = 0;
-
-	if (redo_rseg_undo_ptr != NULL) {
-		ut_ad(mutex_own(&redo_rseg_undo_ptr->rseg->mutex));
-		redo_rseg = redo_rseg_undo_ptr->rseg;
-	}
-
-	if (noredo_rseg_undo_ptr != NULL) {
-		ut_ad(mutex_own(&noredo_rseg_undo_ptr->rseg->mutex));
-		noredo_rseg = noredo_rseg_undo_ptr->rseg;
-	}
+	ut_ad(!rseg || rseg == trx->rsegs.m_redo.rseg);
 
 	trx_sys_mutex_enter();
 
 	trx->no = trx_sys_get_new_trx_id();
 
 	/* Track the minimum serialisation number. */
-	if (!trx->read_only) {
-		UT_LIST_ADD_LAST(trx_sys->serialisation_list, trx);
-		added_trx_no = true;
-	} else {
-		added_trx_no = false;
-	}
+	UT_LIST_ADD_LAST(trx_sys->serialisation_list, trx);
 
 	/* If the rollack segment is not empty then the
 	new trx_t::no can't be less than any trx_t::no
 	already in the rollback segment. User threads only
 	produce events when a rollback segment is empty. */
-	if ((redo_rseg != NULL && redo_rseg->last_page_no == FIL_NULL)
-	    || (noredo_rseg != NULL && noredo_rseg->last_page_no == FIL_NULL)) {
-
+	if (rseg && rseg->last_page_no == FIL_NULL) {
 		TrxUndoRsegs	elem(trx->no);
-
-		if (redo_rseg != NULL && redo_rseg->last_page_no == FIL_NULL) {
-			elem.push_back(redo_rseg);
-		}
-
-		if (noredo_rseg != NULL
-		    && noredo_rseg->last_page_no == FIL_NULL) {
-
-			elem.push_back(noredo_rseg);
-		}
+		elem.push_back(rseg);
 
 		mutex_enter(&purge_sys->pq_mutex);
 
@@ -1542,8 +1343,6 @@ trx_serialisation_number_get(
 	} else {
 		trx_sys_mutex_exit();
 	}
-
-	return(added_trx_no);
 }
 
 /****************************************************************//**
@@ -1566,112 +1365,50 @@ trx_write_serialisation_history(
 	UNDO trx number. This is required for the purge in-memory data
 	structures too. */
 
-	bool	own_redo_rseg_mutex = false;
-	bool	own_noredo_rseg_mutex = false;
-
-	/* Get rollback segment mutex. */
-	if (trx->rsegs.m_redo.rseg != NULL && trx_is_redo_rseg_updated(trx)) {
+	if (trx_undo_t* undo = trx->rsegs.m_noredo.undo) {
+		/* Undo log for temporary tables is discarded at transaction
+		commit. There is no purge for temporary tables, and also no
+		MVCC, because they are private to a session. */
 
-		mutex_enter(&trx->rsegs.m_redo.rseg->mutex);
-		own_redo_rseg_mutex = true;
-	}
-
-	mtr_t	temp_mtr;
-
-	if (trx->rsegs.m_noredo.rseg != NULL
-	    && trx_is_noredo_rseg_updated(trx)) {
-
-		mutex_enter(&trx->rsegs.m_noredo.rseg->mutex);
-		own_noredo_rseg_mutex = true;
-		mtr_start(&temp_mtr);
+		mtr_t	temp_mtr;
+		temp_mtr.start();
 		temp_mtr.set_log_mode(MTR_LOG_NO_REDO);
-	}
 
-	/* If transaction involves insert then truncate undo logs. */
-	if (trx->rsegs.m_redo.insert_undo != NULL) {
-		trx_undo_set_state_at_finish(
-			trx->rsegs.m_redo.insert_undo, mtr);
+		mutex_enter(&trx->rsegs.m_noredo.rseg->mutex);
+		trx_undo_set_state_at_finish(undo, &temp_mtr);
+		mutex_exit(&trx->rsegs.m_noredo.rseg->mutex);
+		temp_mtr.commit();
 	}
 
-	if (trx->rsegs.m_noredo.insert_undo != NULL) {
-		trx_undo_set_state_at_finish(
-			trx->rsegs.m_noredo.insert_undo, &temp_mtr);
+	if (!trx->rsegs.m_redo.rseg) {
+		ut_ad(!trx->rsegs.m_redo.undo);
+		return false;
 	}
 
-	bool	serialised = false;
-
-	/* If transaction involves update then add rollback segments
-	to purge queue. */
-	if (trx->rsegs.m_redo.update_undo != NULL
-	    || trx->rsegs.m_noredo.update_undo != NULL) {
-
-		/* Assign the transaction serialisation number and add these
-		rollback segments to purge trx-no sorted priority queue
-		if this is the first UNDO log being written to assigned
-		rollback segments. */
+	trx_undo_t* undo = trx->rsegs.m_redo.undo;
 
-		trx_undo_ptr_t* redo_rseg_undo_ptr =
-			trx->rsegs.m_redo.update_undo != NULL
-			? &trx->rsegs.m_redo : NULL;
-
-		trx_undo_ptr_t* noredo_rseg_undo_ptr =
-			trx->rsegs.m_noredo.update_undo != NULL
-			? &trx->rsegs.m_noredo : NULL;
-
-		/* Will set trx->no and will add rseg to purge queue. */
-		serialised = trx_serialisation_number_get(
-			trx, redo_rseg_undo_ptr, noredo_rseg_undo_ptr);
-
-		/* It is not necessary to obtain trx->undo_mutex here because
-		only a single OS thread is allowed to do the transaction commit
-		for this transaction. */
-		if (trx->rsegs.m_redo.update_undo != NULL) {
-
-			page_t*		undo_hdr_page;
-
-			undo_hdr_page = trx_undo_set_state_at_finish(
-				trx->rsegs.m_redo.update_undo, mtr);
-
-			/* Delay update of rseg_history_len if we plan to add
-			non-redo update_undo too. This is to avoid immediate
-			invocation of purge as we need to club these 2 segments
-			with same trx-no as single unit. */
-			bool update_rseg_len =
-				!(trx->rsegs.m_noredo.update_undo != NULL);
-
-			trx_undo_update_cleanup(
-				trx, &trx->rsegs.m_redo, undo_hdr_page,
-				update_rseg_len, (update_rseg_len ? 1 : 0),
-				mtr);
-		}
+	if (!undo) {
+		return false;
+	}
 
-		DBUG_EXECUTE_IF("ib_trx_crash_during_commit", DBUG_SUICIDE(););
+	ut_ad(!trx->read_only);
+	trx_rseg_t*	undo_rseg = undo ? undo->rseg : NULL;
+	ut_ad(!undo || undo->rseg == trx->rsegs.m_redo.rseg);
+	mutex_enter(&trx->rsegs.m_redo.rseg->mutex);
 
-		if (trx->rsegs.m_noredo.update_undo != NULL) {
-			page_t*		undo_hdr_page;
+	/* Assign the transaction serialisation number and add any
+	undo log to the purge queue. */
+	trx_serialise(trx, undo_rseg);
 
-			undo_hdr_page = trx_undo_set_state_at_finish(
-				trx->rsegs.m_noredo.update_undo, &temp_mtr);
+	/* It is not necessary to acquire trx->undo_mutex here because
+	only a single OS thread is allowed to commit this transaction. */
 
-			ulint n_added_logs =
-				(redo_rseg_undo_ptr != NULL) ? 2 : 1;
+	/* The undo logs and possible delete-marked records for
+	updates and deletes will be purged later. */
+	page_t*	undo_hdr_page = trx_undo_set_state_at_finish(undo, mtr);
+	trx_undo_update_cleanup(trx, undo_hdr_page, mtr);
 
-			trx_undo_update_cleanup(
-				trx, &trx->rsegs.m_noredo, undo_hdr_page,
-				true, n_added_logs, &temp_mtr);
-		}
-	}
-
-	if (own_redo_rseg_mutex) {
-		mutex_exit(&trx->rsegs.m_redo.rseg->mutex);
-		own_redo_rseg_mutex = false;
-	}
-
-	if (own_noredo_rseg_mutex) {
-		mutex_exit(&trx->rsegs.m_noredo.rseg->mutex);
-		own_noredo_rseg_mutex = false;
-		mtr_commit(&temp_mtr);
-	}
+	mutex_exit(&trx->rsegs.m_redo.rseg->mutex);
 
 	MONITOR_INC(MONITOR_TRX_COMMIT_UNDO);
 
@@ -1690,7 +1427,7 @@ trx_write_serialisation_history(
 		trx->mysql_log_file_name = NULL;
 	}
 
-	return(serialised);
+	return(true);
 }
 
 /********************************************************************
@@ -1978,8 +1715,9 @@ trx_commit_in_memory(
 		}
 	}
 
-	if (trx->rsegs.m_redo.rseg != NULL) {
-		trx_rseg_t*	rseg = trx->rsegs.m_redo.rseg;
+	ut_ad(!trx->rsegs.m_redo.undo);
+
+	if (trx_rseg_t*	rseg = trx->rsegs.m_redo.rseg) {
 		mutex_enter(&rseg->mutex);
 		ut_ad(rseg->trx_ref_count > 0);
 		--rseg->trx_ref_count;
@@ -1987,12 +1725,10 @@ trx_commit_in_memory(
 	}
 
 	if (mtr != NULL) {
-		if (trx->rsegs.m_redo.insert_undo != NULL) {
-			trx_undo_insert_cleanup(&trx->rsegs.m_redo, false);
-		}
-
-		if (trx->rsegs.m_noredo.insert_undo != NULL) {
-			trx_undo_insert_cleanup(&trx->rsegs.m_noredo, true);
+		if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) {
+			ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg);
+			trx_undo_commit_cleanup(undo);
+			undo = NULL;
 		}
 
 		/* NOTE that we could possibly make a group commit more
@@ -2047,6 +1783,8 @@ trx_commit_in_memory(
 		srv_active_wake_master_thread();
 	}
 
+	ut_ad(!trx->rsegs.m_noredo.undo);
+
 	/* Free all savepoints, starting from the first. */
 	trx_named_savept_t*	savep = UT_LIST_GET_FIRST(trx->trx_savepoints);
 
@@ -2209,14 +1947,8 @@ trx_cleanup_at_db_startup(
 	trx_t*	trx)	/*!< in: transaction */
 {
 	ut_ad(trx->is_recovered);
-
-	/* At db start-up there shouldn't be any active trx on temp-table
-	that needs insert_cleanup as temp-table are not visible on
-	restart and temporary rseg is re-created. */
-	if (trx->rsegs.m_redo.insert_undo != NULL) {
-
-		trx_undo_insert_cleanup(&trx->rsegs.m_redo, false);
-	}
+	ut_ad(!trx->rsegs.m_noredo.undo);
+	ut_ad(!trx->rsegs.m_redo.undo);
 
 	memset(&trx->rsegs, 0x0, sizeof(trx->rsegs));
 	trx->undo_no = 0;
@@ -2730,66 +2462,57 @@ trx_weight_ge(
 	return(TRX_WEIGHT(a) >= TRX_WEIGHT(b));
 }
 
-/****************************************************************//**
-Prepares a transaction for given rollback segment.
-@return lsn_t: lsn assigned for commit of scheduled rollback segment */
+/** Prepare a transaction.
+@return	log sequence number that makes the XA PREPARE durable
+@retval	0	if no changes needed to be made durable */
 static
 lsn_t
-trx_prepare_low(
-/*============*/
-	trx_t*		trx,		/*!< in/out: transaction */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in/out: pointer to rollback
-					segment scheduled for prepare. */
-	bool		noredo_logging)	/*!< in: turn-off redo logging. */
+trx_prepare_low(trx_t* trx)
 {
-	lsn_t		lsn;
+	mtr_t	mtr;
 
-	if (undo_ptr->insert_undo != NULL || undo_ptr->update_undo != NULL) {
-		mtr_t		mtr;
-		trx_rseg_t*	rseg = undo_ptr->rseg;
+	/* It is not necessary to acquire trx->undo_mutex here because
+	only the owning (connection) thread of the transaction is
+	allowed to perform XA PREPARE. */
 
-		mtr_start_sync(&mtr);
+	if (trx_undo_t* undo = trx->rsegs.m_noredo.undo) {
+		ut_ad(undo->rseg == trx->rsegs.m_noredo.rseg);
 
-		if (noredo_logging) {
-			mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
-		}
+		mtr.start();
+		mtr.set_log_mode(MTR_LOG_NO_REDO);
 
-		/* Change the undo log segment states from TRX_UNDO_ACTIVE to
-		TRX_UNDO_PREPARED: these modifications to the file data
-		structure define the transaction as prepared in the file-based
-		world, at the serialization point of lsn. */
+		mutex_enter(&undo->rseg->mutex);
+		trx_undo_set_state_at_prepare(trx, undo, false, &mtr);
+		mutex_exit(&undo->rseg->mutex);
 
-		mutex_enter(&rseg->mutex);
+		mtr.commit();
+	}
 
-		if (undo_ptr->insert_undo != NULL) {
+	trx_undo_t* undo = trx->rsegs.m_redo.undo;
 
-			/* It is not necessary to obtain trx->undo_mutex here
-			because only a single OS thread is allowed to do the
-			transaction prepare for this transaction. */
-			trx_undo_set_state_at_prepare(
-				trx, undo_ptr->insert_undo, false, &mtr);
-		}
+	if (!undo) {
+		/* There were no changes to persistent tables. */
+		return(0);
+	}
 
-		if (undo_ptr->update_undo != NULL) {
-			trx_undo_set_state_at_prepare(
-				trx, undo_ptr->update_undo, false, &mtr);
-		}
+	trx_rseg_t*	rseg = trx->rsegs.m_redo.rseg;
+	ut_ad(undo->rseg == rseg);
 
-		mutex_exit(&rseg->mutex);
+	mtr.start(true);
 
-		/*--------------*/
-		/* This mtr commit makes the transaction prepared in
-		file-based world. */
-		mtr_commit(&mtr);
-		/*--------------*/
+	/* Change the undo log segment states from TRX_UNDO_ACTIVE to
+	TRX_UNDO_PREPARED: these modifications to the file data
+	structure define the transaction as prepared in the file-based
+	world, at the serialization point of lsn. */
 
-		lsn = mtr.commit_lsn();
-		ut_ad(noredo_logging || lsn > 0);
-	} else {
-		lsn = 0;
-	}
+	mutex_enter(&rseg->mutex);
+	trx_undo_set_state_at_prepare(trx, undo, false, &mtr);
+	mutex_exit(&rseg->mutex);
 
-	return(lsn);
+	/* Make the XA PREPARE durable. */
+	mtr.commit();
+	ut_ad(mtr.commit_lsn() > 0);
+	return(mtr.commit_lsn());
 }
 
 /****************************************************************//**
@@ -2804,25 +2527,14 @@ trx_prepare(
 	be rolled back asynchronously now. It must commit or rollback
 	synhronously. */
 
-	lsn_t	lsn = 0;
-
 	/* Only fresh user transactions can be prepared.
 	Recovered transactions cannot. */
 	ut_a(!trx->is_recovered);
 
-	if (trx->rsegs.m_redo.rseg != NULL && trx_is_redo_rseg_updated(trx)) {
-
-		lsn = trx_prepare_low(trx, &trx->rsegs.m_redo, false);
-	}
+	lsn_t	lsn = trx_prepare_low(trx);
 
 	DBUG_EXECUTE_IF("ib_trx_crash_during_xa_prepare_step", DBUG_SUICIDE(););
 
-	if (trx->rsegs.m_noredo.rseg != NULL
-	    && trx_is_noredo_rseg_updated(trx)) {
-
-		trx_prepare_low(trx, &trx->rsegs.m_noredo, true);
-	}
-
 	/*--------------------------------------*/
 	ut_a(trx->state == TRX_STATE_ACTIVE);
 	trx_sys_mutex_enter();
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index f1c932c8a84..12c8010e43e 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -106,7 +106,6 @@ void
 trx_undo_page_init(
 /*===============*/
 	page_t* undo_page,	/*!< in: undo log segment page */
-	ulint	type,		/*!< in: undo log segment type */
 	mtr_t*	mtr);		/*!< in: mtr */
 
 #ifndef UNIV_HOTBACKUP
@@ -119,27 +118,12 @@ trx_undo_mem_create(
 /*================*/
 	trx_rseg_t*	rseg,	/*!< in: rollback segment memory object */
 	ulint		id,	/*!< in: slot index within rseg */
-	ulint		type,	/*!< in: type of the log: TRX_UNDO_INSERT or
-				TRX_UNDO_UPDATE */
 	trx_id_t	trx_id,	/*!< in: id of the trx for which the undo log
 				is created */
 	const XID*	xid,	/*!< in: X/Open XA transaction identification*/
 	ulint		page_no,/*!< in: undo log header page number */
 	ulint		offset);/*!< in: undo log header byte offset on page */
 #endif /* !UNIV_HOTBACKUP */
-/***************************************************************//**
-Initializes a cached insert undo log header page for new use. NOTE that this
-function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
-the operation of this function!
-@return undo log header byte offset on page */
-static
-ulint
-trx_undo_insert_header_reuse(
-/*=========================*/
-	page_t*		undo_page,	/*!< in/out: insert undo log segment
-					header page, x-latched */
-	trx_id_t	trx_id,		/*!< in: transaction id */
-	mtr_t*		mtr);		/*!< in: mtr */
 /**********************************************************************//**
 If an update undo log can be discarded immediately, this function frees the
 space, resetting the page to the proper state for caching. */
@@ -367,15 +351,14 @@ void
 trx_undo_page_init_log(
 /*===================*/
 	page_t* undo_page,	/*!< in: undo log page */
-	ulint	type,		/*!< in: undo log type */
 	mtr_t*	mtr)		/*!< in: mtr */
 {
 	mlog_write_initial_log_record(undo_page, MLOG_UNDO_INIT, mtr);
 
-	mlog_catenate_ulint_compressed(mtr, type);
+	mlog_catenate_ulint_compressed(mtr, 0);
 }
 #else /* !UNIV_HOTBACKUP */
-# define trx_undo_page_init_log(undo_page,type,mtr) ((void) 0)
+# define trx_undo_page_init_log(undo_page,mtr) ((void) 0)
 #endif /* !UNIV_HOTBACKUP */
 
 /***********************************************************//**
@@ -389,9 +372,9 @@ trx_undo_parse_page_init(
 	page_t*		page,	/*!< in: page or NULL */
 	mtr_t*		mtr)	/*!< in: mtr or NULL */
 {
-	ulint	type;
-
-	type = mach_parse_compressed(&ptr, end_ptr);
+	if (mach_parse_compressed(&ptr, end_ptr)) {
+		recv_sys->found_corrupt_log = true;
+	}
 
 	if (ptr == NULL) {
 
@@ -399,7 +382,7 @@ trx_undo_parse_page_init(
 	}
 
 	if (page) {
-		trx_undo_page_init(page, type, mtr);
+		trx_undo_page_init(page, mtr);
 	}
 
 	return(const_cast<byte*>(ptr));
@@ -412,14 +395,13 @@ void
 trx_undo_page_init(
 /*===============*/
 	page_t* undo_page,	/*!< in: undo log segment page */
-	ulint	type,		/*!< in: undo log segment type */
 	mtr_t*	mtr)		/*!< in: mtr */
 {
 	trx_upagef_t*	page_hdr;
 
 	page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
 
-	mach_write_to_2(page_hdr + TRX_UNDO_PAGE_TYPE, type);
+	*reinterpret_cast<uint16*>(page_hdr + TRX_UNDO_PAGE_TYPE) = 0;
 
 	mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START,
 			TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_HDR_SIZE);
@@ -428,7 +410,7 @@ trx_undo_page_init(
 
 	fil_page_set_type(undo_page, FIL_PAGE_UNDO_LOG);
 
-	trx_undo_page_init_log(undo_page, type, mtr);
+	trx_undo_page_init_log(undo_page, mtr);
 }
 
 #ifndef UNIV_HOTBACKUP
@@ -443,8 +425,6 @@ trx_undo_seg_create(
 	trx_rseg_t*	rseg MY_ATTRIBUTE((unused)),/*!< in: rollback segment */
 	trx_rsegf_t*	rseg_hdr,/*!< in: rollback segment header, page
 				x-latched */
-	ulint		type,	/*!< in: type of the segment: TRX_UNDO_INSERT or
-				TRX_UNDO_UPDATE */
 	ulint*		id,	/*!< out: slot index within rseg header */
 	page_t**	undo_page,
 				/*!< out: segment header page x-latched, NULL
@@ -465,9 +445,6 @@ trx_undo_seg_create(
 	ut_ad(rseg_hdr != NULL);
 	ut_ad(mutex_own(&(rseg->mutex)));
 
-	/*	fputs(type == TRX_UNDO_INSERT
-	? "Creating insert undo log segment\n"
-	: "Creating update undo log segment\n", stderr); */
 	slot_no = trx_rsegf_undo_find_free(rseg_hdr, mtr);
 
 	if (slot_no == ULINT_UNDEFINED) {
@@ -507,7 +484,7 @@ trx_undo_seg_create(
 	page_hdr = *undo_page + TRX_UNDO_PAGE_HDR;
 	seg_hdr = *undo_page + TRX_UNDO_SEG_HDR;
 
-	trx_undo_page_init(*undo_page, type, mtr);
+	trx_undo_page_init(*undo_page, mtr);
 
 	mlog_write_ulint(page_hdr + TRX_UNDO_PAGE_FREE,
 			 TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE,
@@ -707,27 +684,9 @@ trx_undo_header_add_space_for_xid(
 	mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, new_free,
 			 MLOG_2BYTES, mtr);
 }
+#endif /* UNIV_HOTBACKUP */
 
-/**********************************************************************//**
-Writes the mtr log entry of an undo log header reuse. */
-UNIV_INLINE
-void
-trx_undo_insert_header_reuse_log(
-/*=============================*/
-	const page_t*	undo_page,	/*!< in: undo log header page */
-	trx_id_t	trx_id,		/*!< in: transaction id */
-	mtr_t*		mtr)		/*!< in: mtr */
-{
-	mlog_write_initial_log_record(undo_page, MLOG_UNDO_HDR_REUSE, mtr);
-
-	mlog_catenate_ull_compressed(mtr, trx_id);
-}
-#else /* !UNIV_HOTBACKUP */
-# define trx_undo_insert_header_reuse_log(undo_page,trx_id,mtr) ((void) 0)
-#endif /* !UNIV_HOTBACKUP */
-
-/** Parse the redo log entry of an undo log page header create or reuse.
-@param[in]	type	MLOG_UNDO_HDR_CREATE or MLOG_UNDO_HDR_REUSE
+/** Parse the redo log entry of an undo log page header create.
 @param[in]	ptr	redo log record
 @param[in]	end_ptr	end of log buffer
 @param[in,out]	page	page frame or NULL
@@ -735,7 +694,6 @@ trx_undo_insert_header_reuse_log(
 @return end of log record or NULL */
 byte*
 trx_undo_parse_page_header(
-	mlog_id_t	type,
 	const byte*	ptr,
 	const byte*	end_ptr,
 	page_t*		page,
@@ -744,82 +702,12 @@ trx_undo_parse_page_header(
 	trx_id_t	trx_id = mach_u64_parse_compressed(&ptr, end_ptr);
 
 	if (ptr != NULL && page != NULL) {
-		switch (type) {
-		case MLOG_UNDO_HDR_CREATE:
-			trx_undo_header_create(page, trx_id, mtr);
-			return(const_cast<byte*>(ptr));
-		case MLOG_UNDO_HDR_REUSE:
-			trx_undo_insert_header_reuse(page, trx_id, mtr);
-			return(const_cast<byte*>(ptr));
-		default:
-			break;
-		}
-		ut_ad(0);
+		trx_undo_header_create(page, trx_id, mtr);
 	}
 
 	return(const_cast<byte*>(ptr));
 }
 
-/***************************************************************//**
-Initializes a cached insert undo log header page for new use. NOTE that this
-function has its own log record type MLOG_UNDO_HDR_REUSE. You must NOT change
-the operation of this function!
-@return undo log header byte offset on page */
-static
-ulint
-trx_undo_insert_header_reuse(
-/*=========================*/
-	page_t*		undo_page,	/*!< in/out: insert undo log segment
-					header page, x-latched */
-	trx_id_t	trx_id,		/*!< in: transaction id */
-	mtr_t*		mtr)		/*!< in: mtr */
-{
-	trx_upagef_t*	page_hdr;
-	trx_usegf_t*	seg_hdr;
-	trx_ulogf_t*	log_hdr;
-	ulint		free;
-	ulint		new_free;
-
-	ut_ad(mtr && undo_page);
-
-	page_hdr = undo_page + TRX_UNDO_PAGE_HDR;
-	seg_hdr = undo_page + TRX_UNDO_SEG_HDR;
-
-	free = TRX_UNDO_SEG_HDR + TRX_UNDO_SEG_HDR_SIZE;
-
-	ut_a(free + TRX_UNDO_LOG_XA_HDR_SIZE < UNIV_PAGE_SIZE - 100);
-
-	log_hdr = undo_page + free;
-
-	new_free = free + TRX_UNDO_LOG_OLD_HDR_SIZE;
-
-	/* Insert undo data is not needed after commit: we may free all
-	the space on the page */
-
-	ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
-			      + TRX_UNDO_PAGE_TYPE)
-	     == TRX_UNDO_INSERT);
-
-	mach_write_to_2(page_hdr + TRX_UNDO_PAGE_START, new_free);
-
-	mach_write_to_2(page_hdr + TRX_UNDO_PAGE_FREE, new_free);
-
-	mach_write_to_2(seg_hdr + TRX_UNDO_STATE, TRX_UNDO_ACTIVE);
-
-	log_hdr = undo_page + free;
-
-	mach_write_to_8(log_hdr + TRX_UNDO_TRX_ID, trx_id);
-	mach_write_to_2(log_hdr + TRX_UNDO_LOG_START, new_free);
-
-	mach_write_to_1(log_hdr + TRX_UNDO_XID_EXISTS, FALSE);
-	mach_write_to_1(log_hdr + TRX_UNDO_DICT_TRANS, FALSE);
-
-	/* Write the log record MLOG_UNDO_HDR_REUSE */
-	trx_undo_insert_header_reuse_log(undo_page, trx_id, mtr);
-
-	return(free);
-}
-
 #ifndef UNIV_HOTBACKUP
 /**********************************************************************//**
 Writes the redo log entry of an update undo log header discard. */
@@ -899,35 +787,29 @@ trx_undo_discard_latest_update_undo(
 }
 
 #ifndef UNIV_HOTBACKUP
-/********************************************************************//**
-Tries to add a page to the undo log segment where the undo log is placed.
-@return X-latched block if success, else NULL */
+/** Allocate an undo log page.
+@param[in,out]	trx	transaction
+@param[in,out]	undo	undo log
+@param[in,out]	mtr	mini-transaction that does not hold any page latch
+@return	X-latched block if success
+@retval	NULL	on failure */
 buf_block_t*
-trx_undo_add_page(
-/*==============*/
-	trx_t*		trx,		/*!< in: transaction */
-	trx_undo_t*	undo,		/*!< in: undo log memory object */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: assign undo log from
-					referred rollback segment. */
-	mtr_t*		mtr)		/*!< in: mtr which does not have
-					a latch to any undo log page;
-					the caller must have reserved
-					the rollback segment mutex */
+trx_undo_add_page(trx_t* trx, trx_undo_t* undo, mtr_t* mtr)
 {
-	page_t*		header_page;
-	buf_block_t*	new_block;
-	page_t*		new_page;
-	trx_rseg_t*	rseg;
-	ulint		n_reserved;
+	ut_ad(mutex_own(&trx->undo_mutex));
 
-	ut_ad(mutex_own(&(trx->undo_mutex)));
-	ut_ad(mutex_own(&(undo_ptr->rseg->mutex)));
+	trx_rseg_t*	rseg		= undo->rseg;
+	buf_block_t*	new_block	= NULL;
+	ulint		n_reserved;
+	page_t*		header_page;
 
-	rseg = undo_ptr->rseg;
+	/* When we add a page to an undo log, this is analogous to
+	a pessimistic insert in a B-tree, and we must reserve the
+	counterpart of the tree latch, which is the rseg mutex. */
 
+	mutex_enter(&rseg->mutex);
 	if (rseg->curr_size == rseg->max_size) {
-
-		return(NULL);
+		goto func_exit;
 	}
 
 	header_page = trx_undo_page_get(
@@ -936,8 +818,7 @@ trx_undo_add_page(
 
 	if (!fsp_reserve_free_extents(&n_reserved, undo->space, 1,
 				      FSP_UNDO, mtr)) {
-
-		return(NULL);
+		goto func_exit;
 	}
 
 	new_block = fseg_alloc_free_page_general(
@@ -947,26 +828,26 @@ trx_undo_add_page(
 
 	fil_space_release_free_extents(undo->space, n_reserved);
 
-	if (new_block == NULL) {
-
-		/* No space left */
-
-		return(NULL);
+	if (!new_block) {
+		goto func_exit;
 	}
 
 	ut_ad(rw_lock_get_x_lock_count(&new_block->lock) == 1);
 	buf_block_dbg_add_level(new_block, SYNC_TRX_UNDO_PAGE);
 	undo->last_page_no = new_block->page.id.page_no();
 
-	new_page = buf_block_get_frame(new_block);
+	trx_undo_page_init(new_block->frame, mtr);
 
-	trx_undo_page_init(new_page, undo->type, mtr);
-
-	flst_add_last(header_page + TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST,
-		      new_page + TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE, mtr);
+	flst_add_last(TRX_UNDO_SEG_HDR + TRX_UNDO_PAGE_LIST
+		      + header_page,
+		      TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_NODE
+		      + new_block->frame,
+		      mtr);
 	undo->size++;
 	rseg->curr_size++;
 
+func_exit:
+	mutex_exit(&rseg->mutex);
 	return(new_block);
 }
 
@@ -1027,21 +908,13 @@ trx_undo_free_page(
 	return(last_addr.page);
 }
 
-/********************************************************************//**
-Frees the last undo log page.
-The caller must hold the rollback segment mutex. */
+/** Free the last undo log page. The caller must hold the rseg mutex.
+@param[in,out]	undo	undo log
+@param[in,out]	mtr	mini-transaction that does not hold any undo log page
+			or that has allocated the undo log page */
 void
-trx_undo_free_last_page_func(
-/*==========================*/
-#ifdef UNIV_DEBUG
-	const trx_t*	trx,	/*!< in: transaction */
-#endif /* UNIV_DEBUG */
-	trx_undo_t*	undo,	/*!< in/out: undo log memory copy */
-	mtr_t*		mtr)	/*!< in/out: mini-transaction which does not
-				have a latch to any undo log page or which
-				has allocated the undo log page */
+trx_undo_free_last_page(trx_undo_t* undo, mtr_t* mtr)
 {
-	ut_ad(mutex_own(&trx->undo_mutex));
 	ut_ad(undo->hdr_page_no != undo->last_page_no);
 	ut_ad(undo->size > 0);
 
@@ -1083,49 +956,29 @@ trx_undo_empty_header_page(
 	mlog_write_ulint(log_hdr + TRX_UNDO_LOG_START, end, MLOG_2BYTES, mtr);
 }
 
-/***********************************************************************//**
-Truncates an undo log from the end. This function is used during a rollback
-to free space from an undo log. */
+/** Truncate the tail of an undo log during rollback.
+@param[in,out]	undo	undo log
+@param[in]	limit	all undo logs after this limit will be discarded
+@param[in]	is_temp	whether this is temporary undo log */
 void
-trx_undo_truncate_end_func(
-/*=======================*/
-#ifdef UNIV_DEBUG
-	const trx_t*	trx,	/*!< in: transaction whose undo log it is */
-#endif /* UNIV_DEBUG */
-	trx_undo_t*	undo,	/*!< in: undo log */
-	undo_no_t	limit)	/*!< in: all undo records with undo number
-				>= this value should be truncated */
+trx_undo_truncate_end(trx_undo_t* undo, undo_no_t limit, bool is_temp)
 {
-	page_t*		undo_page;
-	ulint		last_page_no;
-	trx_undo_rec_t* rec;
-	trx_undo_rec_t* trunc_here;
-	mtr_t		mtr;
-	const bool	noredo = trx_sys_is_noredo_rseg_slot(undo->rseg->id);
-
-	ut_ad(mutex_own(&(trx->undo_mutex)));
-
 	ut_ad(mutex_own(&undo->rseg->mutex));
+	ut_ad(is_temp == trx_sys_is_noredo_rseg_slot(undo->rseg->id));
 
 	for (;;) {
-		mtr_start(&mtr);
-		if (noredo) {
+		mtr_t		mtr;
+		mtr.start();
+		if (is_temp) {
 			mtr.set_log_mode(MTR_LOG_NO_REDO);
-			ut_ad(trx->rsegs.m_noredo.rseg == undo->rseg);
-		} else {
-			ut_ad(trx->rsegs.m_redo.rseg == undo->rseg);
 		}
 
-		trunc_here = NULL;
-
-		last_page_no = undo->last_page_no;
-
-		undo_page = trx_undo_page_get(
-			page_id_t(undo->space, last_page_no),
-			undo->page_size, &mtr);
-
-		rec = trx_undo_page_get_last_rec(undo_page, undo->hdr_page_no,
-						 undo->hdr_offset);
+		trx_undo_rec_t* trunc_here = NULL;
+		page_t*		undo_page = trx_undo_page_get(
+			page_id_t(undo->space, undo->last_page_no),
+			undo->rseg->page_size, &mtr);
+		trx_undo_rec_t* rec = trx_undo_page_get_last_rec(
+			undo_page, undo->hdr_page_no, undo->hdr_offset);
 		while (rec) {
 			if (trx_undo_rec_get_undo_no(rec) >= limit) {
 				/* Truncate at least this record off, maybe
@@ -1140,25 +993,22 @@ trx_undo_truncate_end_func(
 							 undo->hdr_offset);
 		}
 
-		if (last_page_no == undo->hdr_page_no) {
+		if (undo->last_page_no == undo->hdr_page_no) {
+function_exit:
+			if (trunc_here) {
+				mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR
+						 + TRX_UNDO_PAGE_FREE,
+						 trunc_here - undo_page,
+						 MLOG_2BYTES, &mtr);
+			}
 
-			goto function_exit;
+			mtr.commit();
+			return;
 		}
 
-		ut_ad(last_page_no == undo->last_page_no);
-		trx_undo_free_last_page(trx, undo, &mtr);
-
-		mtr_commit(&mtr);
-	}
-
-function_exit:
-	if (trunc_here) {
-		mlog_write_ulint(undo_page + TRX_UNDO_PAGE_HDR
-				 + TRX_UNDO_PAGE_FREE,
-				 trunc_here - undo_page, MLOG_2BYTES, &mtr);
+		trx_undo_free_last_page(undo, &mtr);
+		mtr.commit();
 	}
-
-	mtr_commit(&mtr);
 }
 
 /** Truncate the head of an undo log.
@@ -1302,11 +1152,9 @@ trx_undo_mem_create_at_db_start(
 	mtr_t*		mtr)	/*!< in: mtr */
 {
 	page_t*		undo_page;
-	trx_upagef_t*	page_header;
 	trx_usegf_t*	seg_header;
 	trx_ulogf_t*	undo_header;
 	trx_undo_t*	undo;
-	ulint		type;
 	ulint		state;
 	trx_id_t	trx_id;
 	ulint		offset;
@@ -1321,10 +1169,8 @@ trx_undo_mem_create_at_db_start(
 	undo_page = trx_undo_page_get(
 		page_id_t(rseg->space, page_no), rseg->page_size, mtr);
 
-	page_header = undo_page + TRX_UNDO_PAGE_HDR;
-
-	type = mtr_read_ulint(page_header + TRX_UNDO_PAGE_TYPE, MLOG_2BYTES,
-			      mtr);
+	ut_ad(*reinterpret_cast<uint16*>(TRX_UNDO_PAGE_HDR + TRX_UNDO_PAGE_TYPE
+					 + undo_page) == 0);
 	seg_header = undo_page + TRX_UNDO_SEG_HDR;
 
 	state = mach_read_from_2(seg_header + TRX_UNDO_STATE);
@@ -1348,8 +1194,7 @@ trx_undo_mem_create_at_db_start(
 
 	mutex_enter(&(rseg->mutex));
 
-	undo = trx_undo_mem_create(rseg, id, type, trx_id, &xid,
-				   page_no, offset);
+	undo = trx_undo_mem_create(rseg, id, trx_id, &xid, page_no, offset);
 	mutex_exit(&(rseg->mutex));
 
 	undo->dict_operation =	mtr_read_ulint(
@@ -1359,12 +1204,6 @@ trx_undo_mem_create_at_db_start(
 	undo->state = state;
 	undo->size = flst_get_len(seg_header + TRX_UNDO_PAGE_LIST);
 
-	/* If the log segment is being freed, the page list is inconsistent! */
-	if (state == TRX_UNDO_TO_FREE) {
-
-		goto add_to_list;
-	}
-
 	last_addr = flst_get_last(seg_header + TRX_UNDO_PAGE_LIST, mtr);
 
 	undo->last_page_no = last_addr.page;
@@ -1383,28 +1222,12 @@ trx_undo_mem_create_at_db_start(
 		undo->top_offset = rec - last_page;
 		undo->top_undo_no = trx_undo_rec_get_undo_no(rec);
 	}
-add_to_list:
-	if (type == TRX_UNDO_INSERT) {
-		if (state != TRX_UNDO_CACHED) {
-
-			UT_LIST_ADD_LAST(rseg->insert_undo_list, undo);
-		} else {
 
-			UT_LIST_ADD_LAST(rseg->insert_undo_cached, undo);
-
-			MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
-		}
+	if (state != TRX_UNDO_CACHED) {
+		UT_LIST_ADD_LAST(rseg->undo_list, undo);
 	} else {
-		ut_ad(type == TRX_UNDO_UPDATE);
-		if (state != TRX_UNDO_CACHED) {
-
-			UT_LIST_ADD_LAST(rseg->update_undo_list, undo);
-		} else {
-
-			UT_LIST_ADD_LAST(rseg->update_undo_cached, undo);
-
-			MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
-		}
+		UT_LIST_ADD_LAST(rseg->undo_cached, undo);
+		MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
 	}
 
 	return(undo);
@@ -1477,8 +1300,6 @@ trx_undo_mem_create(
 /*================*/
 	trx_rseg_t*	rseg,	/*!< in: rollback segment memory object */
 	ulint		id,	/*!< in: slot index within rseg */
-	ulint		type,	/*!< in: type of the log: TRX_UNDO_INSERT or
-				TRX_UNDO_UPDATE */
 	trx_id_t	trx_id,	/*!< in: id of the trx for which the undo log
 				is created */
 	const XID*	xid,	/*!< in: X/Open transaction identification */
@@ -1499,7 +1320,6 @@ trx_undo_mem_create(
 	}
 
 	undo->id = id;
-	undo->type = type;
 	undo->state = TRX_UNDO_ACTIVE;
 	undo->del_marks = FALSE;
 	undo->trx_id = trx_id;
@@ -1574,8 +1394,6 @@ trx_undo_create(
 /*============*/
 	trx_t*		trx,	/*!< in: transaction */
 	trx_rseg_t*	rseg,	/*!< in: rollback segment memory copy */
-	ulint		type,	/*!< in: type of the log: TRX_UNDO_INSERT or
-				TRX_UNDO_UPDATE */
 	trx_id_t	trx_id,	/*!< in: id of the trx for which the undo log
 				is created */
 	const XID*	xid,	/*!< in: X/Open transaction identification*/
@@ -1602,8 +1420,7 @@ trx_undo_create(
 	rseg_header = trx_rsegf_get(rseg->space, rseg->page_no,
 				    rseg->page_size, mtr);
 
-	err = trx_undo_seg_create(rseg, rseg_header, type, &id,
-				  &undo_page, mtr);
+	err = trx_undo_seg_create(rseg, rseg_header, &id, &undo_page, mtr);
 
 	if (err != DB_SUCCESS) {
 		/* Did not succeed */
@@ -1619,8 +1436,7 @@ trx_undo_create(
 
 	trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr);
 
-	*undo = trx_undo_mem_create(rseg, id, type, trx_id, xid,
-				   page_no, offset);
+	*undo = trx_undo_mem_create(rseg, id, trx_id, xid, page_no, offset);
 	if (*undo == NULL) {
 
 		err = DB_OUT_OF_MEMORY;
@@ -1640,8 +1456,6 @@ trx_undo_reuse_cached(
 /*==================*/
 	trx_t*		trx,	/*!< in: transaction */
 	trx_rseg_t*	rseg,	/*!< in: rollback segment memory object */
-	ulint		type,	/*!< in: type of the log: TRX_UNDO_INSERT or
-				TRX_UNDO_UPDATE */
 	trx_id_t	trx_id,	/*!< in: id of the trx for which the undo log
 				is used */
 	const XID*	xid,	/*!< in: X/Open XA transaction identification */
@@ -1653,30 +1467,12 @@ trx_undo_reuse_cached(
 
 	ut_ad(mutex_own(&(rseg->mutex)));
 
-	if (type == TRX_UNDO_INSERT) {
-
-		undo = UT_LIST_GET_FIRST(rseg->insert_undo_cached);
-		if (undo == NULL) {
-
-			return(NULL);
-		}
-
-		UT_LIST_REMOVE(rseg->insert_undo_cached, undo);
-
-		MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
-	} else {
-		ut_ad(type == TRX_UNDO_UPDATE);
-
-		undo = UT_LIST_GET_FIRST(rseg->update_undo_cached);
-		if (undo == NULL) {
-
-			return(NULL);
-		}
-
-		UT_LIST_REMOVE(rseg->update_undo_cached, undo);
-
-		MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
+	undo = UT_LIST_GET_FIRST(rseg->undo_cached);
+	if (undo == NULL) {
+		return(NULL);
 	}
+	UT_LIST_REMOVE(rseg->undo_cached, undo);
+	MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
 
 	ut_ad(undo->size == 1);
 	ut_a(undo->id < TRX_RSEG_N_SLOTS);
@@ -1685,22 +1481,9 @@ trx_undo_reuse_cached(
 		page_id_t(undo->space, undo->hdr_page_no),
 		undo->page_size, mtr);
 
-	if (type == TRX_UNDO_INSERT) {
-		offset = trx_undo_insert_header_reuse(undo_page, trx_id, mtr);
-
-		trx_undo_header_add_space_for_xid(
-			undo_page, undo_page + offset, mtr);
-	} else {
-		ut_a(mach_read_from_2(undo_page + TRX_UNDO_PAGE_HDR
-				      + TRX_UNDO_PAGE_TYPE)
-		     == TRX_UNDO_UPDATE);
-
-		offset = trx_undo_header_create(undo_page, trx_id, mtr);
-
-		trx_undo_header_add_space_for_xid(
-			undo_page, undo_page + offset, mtr);
-	}
+	offset = trx_undo_header_create(undo_page, trx_id, mtr);
 
+	trx_undo_header_add_space_for_xid(undo_page, undo_page + offset, mtr);
 	trx_undo_mem_init_for_reuse(undo, trx_id, xid, offset);
 
 	return(undo);
@@ -1745,90 +1528,56 @@ trx_undo_mark_as_dict_operation(
 	undo->dict_operation = TRUE;
 }
 
-/**********************************************************************//**
-Assigns an undo log for a transaction. A new undo log is created or a cached
-undo log reused.
-@return DB_SUCCESS if undo log assign successful, possible error codes
-are: DB_TOO_MANY_CONCURRENT_TRXS DB_OUT_OF_FILE_SPACE DB_READ_ONLY
-DB_OUT_OF_MEMORY */
+/** Assign an undo log for a transaction.
+A new undo log is created or a cached undo log reused.
+@param[in,out]	trx	transaction
+@param[in]	rseg	rollback segment
+@param[out]	undo	the undo log
+@retval	DB_SUCCESS	on success
+@retval	DB_TOO_MANY_CONCURRENT_TRXS
+@retval	DB_OUT_OF_FILE_SPACE
+@retval	DB_READ_ONLY
+@retval DB_OUT_OF_MEMORY */
 dberr_t
-trx_undo_assign_undo(
-/*=================*/
-	trx_t*		trx,		/*!< in: transaction */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: assign undo log from
-					referred rollback segment. */
-	ulint		type)		/*!< in: TRX_UNDO_INSERT or
-					TRX_UNDO_UPDATE */
+trx_undo_assign_undo(trx_t* trx, trx_rseg_t* rseg, trx_undo_t** undo)
 {
-	trx_rseg_t*	rseg;
-	trx_undo_t*	undo;
+	const bool	is_temp = rseg == trx->rsegs.m_noredo.rseg;
 	mtr_t		mtr;
 	dberr_t		err = DB_SUCCESS;
 
-	ut_ad(trx);
-
-	/* In case of read-only scenario trx->rsegs.m_redo.rseg can be NULL but
-	still request for assigning undo logs is valid as temporary tables
-	can be updated in read-only mode.
-	If there is no rollback segment assigned to trx and still there is
-	object being updated there is something wrong and so this condition
-	check. */
-	ut_ad(trx_is_rseg_assigned(trx));
-
-	rseg = undo_ptr->rseg;
+	ut_ad(mutex_own(&trx->undo_mutex));
+	ut_ad(rseg == trx->rsegs.m_redo.rseg
+	      || rseg == trx->rsegs.m_noredo.rseg);
+	ut_ad(undo == (is_temp
+		       ? &trx->rsegs.m_noredo.undo
+		       : &trx->rsegs.m_redo.undo));
 
-	ut_ad(mutex_own(&(trx->undo_mutex)));
+	mtr.start();
 
-	mtr_start(&mtr);
-	if (&trx->rsegs.m_noredo == undo_ptr) {
-		mtr.set_log_mode(MTR_LOG_NO_REDO);;
-	} else {
-		ut_ad(&trx->rsegs.m_redo == undo_ptr);
-	}
-
-	if (trx_sys_is_noredo_rseg_slot(rseg->id)) {
-		mtr.set_log_mode(MTR_LOG_NO_REDO);;
-		ut_ad(undo_ptr == &trx->rsegs.m_noredo);
-	} else {
-		ut_ad(undo_ptr == &trx->rsegs.m_redo);
+	if (is_temp) {
+		mtr.set_log_mode(MTR_LOG_NO_REDO);
 	}
 
 	mutex_enter(&rseg->mutex);
 
-	DBUG_EXECUTE_IF(
-		"ib_create_table_fail_too_many_trx",
-		err = DB_TOO_MANY_CONCURRENT_TRXS;
-		goto func_exit;
-	);
-
-	undo = trx_undo_reuse_cached(trx, rseg, type, trx->id, trx->xid,
-				     &mtr);
-	if (undo == NULL) {
-		err = trx_undo_create(trx, rseg, type, trx->id, trx->xid,
-				      &undo, &mtr);
+	*undo = trx_undo_reuse_cached(trx, rseg, trx->id, trx->xid, &mtr);
+	if (*undo == NULL) {
+		err = trx_undo_create(trx, rseg, trx->id, trx->xid,
+				      undo, &mtr);
 		if (err != DB_SUCCESS) {
-
 			goto func_exit;
 		}
 	}
 
-	if (type == TRX_UNDO_INSERT) {
-		UT_LIST_ADD_FIRST(rseg->insert_undo_list, undo);
-		ut_ad(undo_ptr->insert_undo == NULL);
-		undo_ptr->insert_undo = undo;
-	} else {
-		UT_LIST_ADD_FIRST(rseg->update_undo_list, undo);
-		ut_ad(undo_ptr->update_undo == NULL);
-		undo_ptr->update_undo = undo;
-	}
+	UT_LIST_ADD_FIRST(rseg->undo_list, *undo);
 
-	if (trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
-		trx_undo_mark_as_dict_operation(trx, undo, &mtr);
+	if (!is_temp && trx_get_dict_operation(trx) != TRX_DICT_OP_NONE) {
+		trx_undo_mark_as_dict_operation(trx, *undo, &mtr);
 	}
 
 func_exit:
-	mutex_exit(&(rseg->mutex));
-	mtr_commit(&mtr);
+	mutex_exit(&rseg->mutex);
+	mtr.commit();
 
 	return(err);
 }
@@ -1861,10 +1610,6 @@ trx_undo_set_state_at_finish(
 	       < TRX_UNDO_PAGE_REUSE_LIMIT) {
 
 		state = TRX_UNDO_CACHED;
-
-	} else if (undo->type == TRX_UNDO_INSERT) {
-
-		state = TRX_UNDO_TO_FREE;
 	} else {
 		state = TRX_UNDO_TO_PURGE;
 	}
@@ -1878,7 +1623,7 @@ trx_undo_set_state_at_finish(
 
 /** Set the state of the undo log segment at a XA PREPARE or XA ROLLBACK.
 @param[in,out]	trx		transaction
-@param[in,out]	undo		insert_undo or update_undo log
+@param[in,out]	undo		undo log
 @param[in]	rollback	false=XA PREPARE, true=XA ROLLBACK
 @param[in,out]	mtr		mini-transaction
 @return undo log segment header page, x-latched */
@@ -1940,34 +1685,24 @@ trx_undo_update_cleanup(
 /*====================*/
 	trx_t*		trx,		/*!< in: trx owning the update
 					undo log */
-	trx_undo_ptr_t*	undo_ptr,	/*!< in: update undo log. */
 	page_t*		undo_page,	/*!< in: update undo log header page,
 					x-latched */
-	bool		update_rseg_history_len,
-					/*!< in: if true: update rseg history
-					len else skip updating it. */
-	ulint		n_added_logs,	/*!< in: number of logs added */
 	mtr_t*		mtr)		/*!< in: mtr */
 {
-	trx_rseg_t*	rseg;
-	trx_undo_t*	undo;
-
-	undo = undo_ptr->update_undo;
-	rseg = undo_ptr->rseg;
+	trx_undo_t*	undo	= trx->rsegs.m_redo.undo;
+	trx_rseg_t*	rseg	= undo->rseg;
 
-	ut_ad(mutex_own(&(rseg->mutex)));
+	ut_ad(mutex_own(&rseg->mutex));
 
-	trx_purge_add_update_undo_to_history(
-		trx, undo_ptr, undo_page,
-		update_rseg_history_len, n_added_logs, mtr);
+	trx_purge_add_update_undo_to_history(trx, undo_page, mtr);
 
-	UT_LIST_REMOVE(rseg->update_undo_list, undo);
+	UT_LIST_REMOVE(rseg->undo_list, undo);
 
-	undo_ptr->update_undo = NULL;
+	trx->rsegs.m_redo.undo = NULL;
 
 	if (undo->state == TRX_UNDO_CACHED) {
 
-		UT_LIST_ADD_FIRST(rseg->update_undo_cached, undo);
+		UT_LIST_ADD_FIRST(rseg->undo_cached, undo);
 
 		MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
 	} else {
@@ -1977,55 +1712,38 @@ trx_undo_update_cleanup(
 	}
 }
 
-/** Frees an insert undo log after a transaction commit or rollback.
-Knowledge of inserts is not needed after a commit or rollback, therefore
+/** Free a temporary undo log after commit or rollback.
+The information is not needed after a commit or rollback, therefore
 the data can be discarded.
-@param[in,out]	undo_ptr	undo log to clean up
-@param[in]	noredo		whether the undo tablespace is redo logged */
+@param[in,out]	undo	undo log */
 void
-trx_undo_insert_cleanup(
-	trx_undo_ptr_t*	undo_ptr,
-	bool		noredo)
+trx_undo_commit_cleanup(trx_undo_t* undo)
 {
-	trx_undo_t*	undo;
-	trx_rseg_t*	rseg;
-
-	undo = undo_ptr->insert_undo;
-	ut_ad(undo != NULL);
-
-	rseg = undo_ptr->rseg;
+	trx_rseg_t*	rseg	= undo->rseg;
+	ut_ad(trx_sys_is_noredo_rseg_slot(rseg->id));
 
-	ut_ad(noredo == trx_sys_is_noredo_rseg_slot(rseg->id));
-
-	mutex_enter(&(rseg->mutex));
+	mutex_enter(&rseg->mutex);
 
-	UT_LIST_REMOVE(rseg->insert_undo_list, undo);
-	undo_ptr->insert_undo = NULL;
+	UT_LIST_REMOVE(rseg->undo_list, undo);
 
 	if (undo->state == TRX_UNDO_CACHED) {
-
-		UT_LIST_ADD_FIRST(rseg->insert_undo_cached, undo);
-
+		UT_LIST_ADD_FIRST(rseg->undo_cached, undo);
 		MONITOR_INC(MONITOR_NUM_UNDO_SLOT_CACHED);
 	} else {
-		ut_ad(undo->state == TRX_UNDO_TO_FREE);
+		ut_ad(undo->state == TRX_UNDO_TO_PURGE);
 
 		/* Delete first the undo log segment in the file */
-
-		mutex_exit(&(rseg->mutex));
-
-		trx_undo_seg_free(undo, noredo);
-
-		mutex_enter(&(rseg->mutex));
+		mutex_exit(&rseg->mutex);
+		trx_undo_seg_free(undo, true);
+		mutex_enter(&rseg->mutex);
 
 		ut_ad(rseg->curr_size > undo->size);
-
 		rseg->curr_size -= undo->size;
 
 		trx_undo_mem_free(undo);
 	}
 
-	mutex_exit(&(rseg->mutex));
+	mutex_exit(&rseg->mutex);
 }
 
 /********************************************************************//**
@@ -2037,45 +1755,32 @@ trx_undo_free_prepared(
 {
 	ut_ad(srv_shutdown_state == SRV_SHUTDOWN_EXIT_THREADS);
 
-	if (trx->rsegs.m_redo.update_undo) {
-		ut_a(trx->rsegs.m_redo.update_undo->state == TRX_UNDO_PREPARED);
-		UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->update_undo_list,
-			       trx->rsegs.m_redo.update_undo);
-		trx_undo_mem_free(trx->rsegs.m_redo.update_undo);
-
-		trx->rsegs.m_redo.update_undo = NULL;
-	}
-
-	if (trx->rsegs.m_redo.insert_undo) {
-		ut_a(trx->rsegs.m_redo.insert_undo->state == TRX_UNDO_PREPARED);
-		UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->insert_undo_list,
-			       trx->rsegs.m_redo.insert_undo);
-		trx_undo_mem_free(trx->rsegs.m_redo.insert_undo);
-
-		trx->rsegs.m_redo.insert_undo = NULL;
-	}
-
-	if (trx->rsegs.m_noredo.update_undo) {
-
-		ut_a(trx->rsegs.m_noredo.update_undo->state
-			== TRX_UNDO_PREPARED);
-
-		UT_LIST_REMOVE(trx->rsegs.m_noredo.rseg->update_undo_list,
-			       trx->rsegs.m_noredo.update_undo);
-		trx_undo_mem_free(trx->rsegs.m_noredo.update_undo);
+	if (trx_undo_t*& undo = trx->rsegs.m_redo.undo) {
+		switch (undo->state) {
+		case TRX_UNDO_PREPARED:
+			break;
+		case TRX_UNDO_ACTIVE:
+			/* lock_trx_release_locks() assigns
+			trx->is_recovered=false */
+			ut_a(!srv_was_started
+			     || srv_read_only_mode
+			     || srv_force_recovery >= SRV_FORCE_NO_TRX_UNDO);
+			break;
+		default:
+			ut_error;
+		}
 
-		trx->rsegs.m_noredo.update_undo = NULL;
+		UT_LIST_REMOVE(trx->rsegs.m_redo.rseg->undo_list, undo);
+		trx_undo_mem_free(undo);
+		undo = NULL;
 	}
-	if (trx->rsegs.m_noredo.insert_undo) {
-
-		ut_a(trx->rsegs.m_noredo.insert_undo->state
-			== TRX_UNDO_PREPARED);
 
-		UT_LIST_REMOVE(trx->rsegs.m_noredo.rseg->insert_undo_list,
-			       trx->rsegs.m_noredo.insert_undo);
-		trx_undo_mem_free(trx->rsegs.m_noredo.insert_undo);
+	if (trx_undo_t*& undo = trx->rsegs.m_noredo.undo) {
+		ut_a(undo->state == TRX_UNDO_PREPARED);
 
-		trx->rsegs.m_noredo.insert_undo = NULL;
+		UT_LIST_REMOVE(trx->rsegs.m_noredo.rseg->undo_list, undo);
+		trx_undo_mem_free(undo);
+		undo = NULL;
 	}
 }
 
@@ -2126,37 +1831,22 @@ trx_undo_truncate_tablespace(
 
 		/* Before re-initialization ensure that we free the existing
 		structure. There can't be any active transactions. */
-		ut_a(UT_LIST_GET_LEN(rseg->update_undo_list) == 0);
-		ut_a(UT_LIST_GET_LEN(rseg->insert_undo_list) == 0);
+		ut_a(UT_LIST_GET_LEN(rseg->undo_list) == 0);
 
 		trx_undo_t*	next_undo;
 
-		for (trx_undo_t* undo =
-			UT_LIST_GET_FIRST(rseg->update_undo_cached);
-		     undo != NULL;
-		     undo = next_undo) {
-
-			next_undo = UT_LIST_GET_NEXT(undo_list, undo);
-			UT_LIST_REMOVE(rseg->update_undo_cached, undo);
-			MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
-			trx_undo_mem_free(undo);
-		}
-
-		for (trx_undo_t* undo =
-			UT_LIST_GET_FIRST(rseg->insert_undo_cached);
+		for (trx_undo_t* undo = UT_LIST_GET_FIRST(rseg->undo_cached);
 		     undo != NULL;
 		     undo = next_undo) {
 
 			next_undo = UT_LIST_GET_NEXT(undo_list, undo);
-			UT_LIST_REMOVE(rseg->insert_undo_cached, undo);
+			UT_LIST_REMOVE(rseg->undo_cached, undo);
 			MONITOR_DEC(MONITOR_NUM_UNDO_SLOT_CACHED);
 			trx_undo_mem_free(undo);
 		}
 
-		UT_LIST_INIT(rseg->update_undo_list, &trx_undo_t::undo_list);
-		UT_LIST_INIT(rseg->update_undo_cached, &trx_undo_t::undo_list);
-		UT_LIST_INIT(rseg->insert_undo_list, &trx_undo_t::undo_list);
-		UT_LIST_INIT(rseg->insert_undo_cached, &trx_undo_t::undo_list);
+		UT_LIST_INIT(rseg->undo_list, &trx_undo_t::undo_list);
+		UT_LIST_INIT(rseg->undo_cached, &trx_undo_t::undo_list);
 
 		rseg->max_size = mtr_read_ulint(
 			rseg_header + TRX_RSEG_MAX_SIZE, MLOG_4BYTES, &mtr);
-- 
2.11.0

