diff --git a/storage/innobase/dict/dict0crea.cc b/storage/innobase/dict/dict0crea.cc
index a83ee896972..81f5e0bffc7 100644
--- a/storage/innobase/dict/dict0crea.cc
+++ b/storage/innobase/dict/dict0crea.cc
@@ -1677,16 +1677,11 @@ dict_create_or_check_foreign_constraint_tables(void)
 	/* Check which incomplete table definition to drop. */
 
 	if (sys_foreign_err == DB_CORRUPTION) {
-		ib::warn() << "Dropping incompletely created"
-			" SYS_FOREIGN table.";
-		row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
+		row_drop_table_after_create_fail("SYS_FOREIGN", trx);
 	}
 
 	if (sys_foreign_cols_err == DB_CORRUPTION) {
-		ib::warn() << "Dropping incompletely created"
-			" SYS_FOREIGN_COLS table.";
-
-		row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);
+		row_drop_table_after_create_fail("SYS_FOREIGN_COLS", trx);
 	}
 
 	ib::info() << "Creating foreign key constraint system tables.";
@@ -1738,8 +1733,8 @@ dict_create_or_check_foreign_constraint_tables(void)
 		ut_ad(err == DB_OUT_OF_FILE_SPACE
 		      || err == DB_TOO_MANY_CONCURRENT_TRXS);
 
-		row_drop_table_for_mysql("SYS_FOREIGN", trx, TRUE, TRUE);
-		row_drop_table_for_mysql("SYS_FOREIGN_COLS", trx, TRUE, TRUE);
+		row_drop_table_after_create_fail("SYS_FOREIGN", trx);
+		row_drop_table_after_create_fail("SYS_FOREIGN_COLS", trx);
 
 		if (err == DB_OUT_OF_FILE_SPACE) {
 			err = DB_MUST_GET_MORE_FILE_SPACE;
@@ -1807,9 +1802,7 @@ dict_create_or_check_sys_virtual()
 	/* Check which incomplete table definition to drop. */
 
 	if (err == DB_CORRUPTION) {
-		ib::warn() << "Dropping incompletely created"
-			" SYS_VIRTUAL table.";
-		row_drop_table_for_mysql("SYS_VIRTUAL", trx, false, TRUE);
+		row_drop_table_after_create_fail("SYS_VIRTUAL", trx);
 	}
 
 	ib::info() << "Creating sys_virtual system tables.";
@@ -1843,7 +1836,7 @@ dict_create_or_check_sys_virtual()
 		ut_ad(err == DB_OUT_OF_FILE_SPACE
 		      || err == DB_TOO_MANY_CONCURRENT_TRXS);
 
-		row_drop_table_for_mysql("SYS_VIRTUAL", trx, false, TRUE);
+		row_drop_table_after_create_fail("SYS_VIRTUAL", trx);
 
 		if (err == DB_OUT_OF_FILE_SPACE) {
 			err = DB_MUST_GET_MORE_FILE_SPACE;
@@ -2462,16 +2455,11 @@ dict_create_or_check_sys_tablespace(void)
 	/* Check which incomplete table definition to drop. */
 
 	if (sys_tablespaces_err == DB_CORRUPTION) {
-		ib::warn() << "Dropping incompletely created"
-			" SYS_TABLESPACES table.";
-		row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE);
+		row_drop_table_after_create_fail("SYS_TABLESPACES", trx);
 	}
 
 	if (sys_datafiles_err == DB_CORRUPTION) {
-		ib::warn() << "Dropping incompletely created"
-			" SYS_DATAFILES table.";
-
-		row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE);
+		row_drop_table_after_create_fail("SYS_DATAFILES", trx);
 	}
 
 	ib::info() << "Creating tablespace and datafile system tables.";
@@ -2506,8 +2494,8 @@ dict_create_or_check_sys_tablespace(void)
 		     || err == DB_DUPLICATE_KEY
 		     || err == DB_TOO_MANY_CONCURRENT_TRXS);
 
-		row_drop_table_for_mysql("SYS_TABLESPACES", trx, TRUE, TRUE);
-		row_drop_table_for_mysql("SYS_DATAFILES", trx, TRUE, TRUE);
+		row_drop_table_after_create_fail("SYS_TABLESPACES", trx);
+		row_drop_table_after_create_fail("SYS_DATAFILES", trx);
 
 		if (err == DB_OUT_OF_FILE_SPACE) {
 			err = DB_MUST_GET_MORE_FILE_SPACE;
diff --git a/storage/innobase/fil/fil0fil.cc b/storage/innobase/fil/fil0fil.cc
index feebe5d2162..53c95816b12 100644
--- a/storage/innobase/fil/fil0fil.cc
+++ b/storage/innobase/fil/fil0fil.cc
@@ -2819,8 +2819,6 @@ fil_check_pending_operations(
 
 	/* Check for pending IO. */
 
-	*path = 0;
-
 	for (;;) {
 		sp = fil_space_get_by_id(id);
 
@@ -2833,7 +2831,7 @@ fil_check_pending_operations(
 
 		count = fil_check_pending_io(operation, sp, &node, count);
 
-		if (count == 0) {
+		if (count == 0 && path) {
 			*path = mem_strdup(node->name);
 		}
 
@@ -3068,152 +3066,33 @@ fil_delete_tablespace(
 	return(err);
 }
 
-/** Truncate the tablespace to needed size.
-@param[in]	space_id	id of tablespace to truncate
-@param[in]	size_in_pages	truncate size.
-@return true if truncate was successful. */
-bool
-fil_truncate_tablespace(
-	ulint		space_id,
-	ulint		size_in_pages)
-{
-	/* Step-1: Prepare tablespace for truncate. This involves
-	stopping all the new operations + IO on that tablespace
-	and ensuring that related pages are flushed to disk. */
-	if (fil_prepare_for_truncate(space_id) != DB_SUCCESS) {
-		return(false);
-	}
-
-	/* Step-2: Invalidate buffer pool pages belonging to the tablespace
-	to re-create. Remove all insert buffer entries for the tablespace */
-	buf_LRU_flush_or_remove_pages(space_id, NULL);
-
-	/* Step-3: Truncate the tablespace and accordingly update
-	the fil_space_t handler that is used to access this tablespace. */
-	mutex_enter(&fil_system->mutex);
-	fil_space_t*	space = fil_space_get_by_id(space_id);
-
-	/* The following code must change when InnoDB supports
-	multiple datafiles per tablespace. */
-	ut_a(UT_LIST_GET_LEN(space->chain) == 1);
-
-	fil_node_t*	node = UT_LIST_GET_FIRST(space->chain);
-
-	ut_ad(node->is_open());
-
-	space->size = node->size = size_in_pages;
-
-	bool success = os_file_truncate(node->name, node->handle, 0);
-	if (success) {
-
-		os_offset_t	size = os_offset_t(size_in_pages) * UNIV_PAGE_SIZE;
-
-		success = os_file_set_size(
-			node->name, node->handle, size,
-			FSP_FLAGS_HAS_PAGE_COMPRESSION(space->flags));
-
-		if (success) {
-			space->stop_new_ops = false;
-			space->is_being_truncated = false;
-		}
-	}
-
-	mutex_exit(&fil_system->mutex);
-
-	return(success);
-}
-
-/*******************************************************************//**
-Prepare for truncating a single-table tablespace.
-1) Check pending operations on a tablespace;
-2) Remove all insert buffer entries for the tablespace;
-@return DB_SUCCESS or error */
-dberr_t
-fil_prepare_for_truncate(
-/*=====================*/
-	ulint	id)		/*!< in: space id */
+/** Prepare to truncate a tablespace.
+@param[in]	space_id	tablespace id
+@return	the tablespace
+@retval	NULL if tablespace not found */
+fil_space_t* fil_truncate_prepare(ulint space_id)
 {
-	char*		path = 0;
-	fil_space_t*	space = 0;
-
-	ut_a(!is_system_tablespace(id));
-
-	dberr_t	err = fil_check_pending_operations(
-		id, FIL_OPERATION_TRUNCATE, &space, &path);
-
-	ut_free(path);
-
-	if (err == DB_TABLESPACE_NOT_FOUND) {
-		ib::error() << "Cannot truncate tablespace " << id
-			<< " because it is not found in the tablespace"
-			" memory cache.";
+	/* Stop all I/O on the tablespace and ensure that related
+	pages are flushed to disk. */
+	fil_space_t* space;
+	if (fil_check_pending_operations(space_id, FIL_OPERATION_TRUNCATE,
+					 &space, NULL) != DB_SUCCESS) {
+		return NULL;
 	}
-
-	return(err);
+	ut_ad(space != NULL);
+	return space;
 }
 
-/** Reinitialize the original tablespace header with the same space id
-for single tablespace
-@param[in]      table		table belongs to tablespace
-@param[in]      size            size in blocks
-@param[in]      trx             Transaction covering truncate */
-void
-fil_reinit_space_header_for_table(
-	dict_table_t*	table,
-	ulint		size,
-	trx_t*		trx)
+/** Write log about a truncate operation. */
+void fil_truncate_log(fil_space_t* space, ulint size, mtr_t* mtr)
 {
-	ulint	id = table->space;
-
-	ut_a(!is_system_tablespace(id));
-
-	/* Invalidate in the buffer pool all pages belonging
-	to the tablespace. The buffer pool scan may take long
-	time to complete, therefore we release dict_sys->mutex
-	and the dict operation lock during the scan and aquire
-	it again after the buffer pool scan.*/
-
-	/* Release the lock on the indexes too. So that
-	they won't violate the latch ordering. */
-	dict_table_x_unlock_indexes(table);
-	row_mysql_unlock_data_dictionary(trx);
-
-	/* Lock the search latch in shared mode to prevent user
-	from disabling AHI during the scan */
-	btr_search_s_lock_all();
-	DEBUG_SYNC_C("buffer_pool_scan");
-	buf_LRU_flush_or_remove_pages(id, NULL);
-	btr_search_s_unlock_all();
-
-	row_mysql_lock_data_dictionary(trx);
-
-	dict_table_x_lock_indexes(table);
-
-	/* Remove all insert buffer entries for the tablespace */
-	ibuf_delete_for_discarded_space(id);
-
-	mutex_enter(&fil_system->mutex);
-
-	fil_space_t*	space = fil_space_get_by_id(id);
-
-	/* The following code must change when InnoDB supports
-	multiple datafiles per tablespace. */
-	ut_a(UT_LIST_GET_LEN(space->chain) == 1);
-
-	fil_node_t*	node = UT_LIST_GET_FIRST(space->chain);
-
-	space->size = node->size = size;
-
-	mutex_exit(&fil_system->mutex);
-
-	mtr_t	mtr;
-
-	mtr_start(&mtr);
-	mtr.set_named_space(id);
-
-	fsp_header_init(id, size, &mtr);
-
-	mtr_commit(&mtr);
+	/* Write a MLOG_FILE_CREATE2 record with the new size, so that
+	recovery and backup will ignore any preceding redo log records
+	for writing pages that are after the new end of the tablespace. */
+	ut_ad(UT_LIST_GET_LEN(space->chain) == 1);
+	const fil_node_t* file = UT_LIST_GET_FIRST(space->chain);
+	fil_op_write_log(MLOG_FILE_CREATE2, space->id, size, file->name,
+			 NULL, space->flags & ~FSP_FLAGS_MEM_MASK, mtr);
 }
 
 #ifdef UNIV_DEBUG
@@ -5085,7 +4964,6 @@ fil_io(
 			if (space->id != TRX_SYS_SPACE
 			    && UT_LIST_GET_LEN(space->chain) == 1
 			    && (srv_is_tablespace_truncated(space->id)
-				|| space->is_being_truncated
 				|| srv_was_tablespace_truncated(space))
 			    && req_type.is_read()) {
 
@@ -5766,7 +5644,7 @@ fil_space_validate_for_mtr_commit(
 	fil_space_release() after mtr_commit(). This is why
 	n_pending_ops should not be zero if stop_new_ops is set. */
 	ut_ad(!space->stop_new_ops
-	      || space->is_being_truncated /* TRUNCATE sets stop_new_ops */
+	      || space->is_being_truncated /* fil_truncate_prepare() */
 	      || space->n_pending_ops > 0);
 }
 #endif /* UNIV_DEBUG */
@@ -5992,7 +5870,6 @@ truncate_t::truncate(
 	}
 
 	space->stop_new_ops = false;
-	space->is_being_truncated = false;
 
 	/* If we opened the file in this function, close it. */
 	if (!already_open) {
diff --git a/storage/innobase/fsp/fsp0fsp.cc b/storage/innobase/fsp/fsp0fsp.cc
index d4d5abeb32f..6ddcff7a55a 100644
--- a/storage/innobase/fsp/fsp0fsp.cc
+++ b/storage/innobase/fsp/fsp0fsp.cc
@@ -639,7 +639,6 @@ fsp_space_modify_check(
 		ut_ad(space->purpose == FIL_TYPE_TEMPORARY
 		      || space->purpose == FIL_TYPE_IMPORT
 		      || space->redo_skipped_count
-		      || space->is_being_truncated
 		      || srv_is_tablespace_truncated(space->id));
 		return;
 	case MTR_LOG_ALL:
diff --git a/storage/innobase/fts/fts0fts.cc b/storage/innobase/fts/fts0fts.cc
index 81ec3a3c80e..25a9595b833 100644
--- a/storage/innobase/fts/fts0fts.cc
+++ b/storage/innobase/fts/fts0fts.cc
@@ -1470,7 +1470,8 @@ fts_drop_table(
 		/* Pass nonatomic=false (dont allow data dict unlock),
 		because the transaction may hold locks on SYS_* tables from
 		previous calls to fts_drop_table(). */
-		error = row_drop_table_for_mysql(table_name, trx, true, false, false);
+		error = row_drop_table_for_mysql(table_name, trx,
+						 SQLCOM_DROP_DB, false, false);
 
 		if (error != DB_SUCCESS) {
 			ib::error() << "Unable to drop FTS index aux table "
@@ -1944,8 +1945,8 @@ fts_create_common_tables(
 	if (error != DB_SUCCESS) {
 		for (it = common_tables.begin(); it != common_tables.end();
 		     ++it) {
-			row_drop_table_for_mysql(
-				(*it)->name.m_name, trx, true, FALSE);
+			row_drop_table_for_mysql((*it)->name.m_name, trx,
+						 SQLCOM_DROP_DB, false);
 		}
 	}
 
@@ -2105,8 +2106,8 @@ fts_create_index_tables_low(
 
 		for (it = aux_idx_tables.begin(); it != aux_idx_tables.end();
 		     ++it) {
-			row_drop_table_for_mysql(
-				(*it)->name.m_name, trx, true, FALSE);
+			row_drop_table_for_mysql((*it)->name.m_name, trx,
+						 SQLCOM_DROP_DB, false);
 		}
 	}
 
@@ -6712,7 +6713,8 @@ fts_drop_obsolete_aux_table_from_vector(
 		trx_start_for_ddl(trx_drop, TRX_DICT_OP_TABLE);
 
 		err = row_drop_table_for_mysql(
-			aux_drop_table->name, trx_drop, false, true);
+			aux_drop_table->name, trx_drop,
+			SQLCOM_DROP_TABLE, true);
 
 		trx_drop->dict_operation_lock_mode = 0;
 
diff --git a/storage/innobase/handler/ha_innodb.cc b/storage/innobase/handler/ha_innodb.cc
index d8e805862f7..b6029e539b8 100644
--- a/storage/innobase/handler/ha_innodb.cc
+++ b/storage/innobase/handler/ha_innodb.cc
@@ -3833,10 +3833,7 @@ innobase_init(
         innobase_hton->fake_trx_id=wsrep_fake_trx_id;
 #endif /* WITH_WSREP */
 
-        if (srv_file_per_table) {
-		innobase_hton->tablefile_extensions = ha_innobase_exts;
-	}
-
+	innobase_hton->tablefile_extensions = ha_innobase_exts;
 	innobase_hton->table_options = innodb_table_option_list;
 
 	innodb_remember_check_sysvar_funcs();
@@ -12830,7 +12827,8 @@ create_table_info_t::create_table()
 			trx_rollback_to_savepoint(m_trx, NULL);
 			m_trx->error_state = DB_SUCCESS;
 
-			row_drop_table_for_mysql(m_table_name, m_trx, true, FALSE);
+			row_drop_table_for_mysql(m_table_name, m_trx,
+						 SQLCOM_DROP_DB, false);
 
 			m_trx->error_state = DB_SUCCESS;
 			DBUG_RETURN(error);
@@ -13026,24 +13024,29 @@ create_table_info_t::allocate_trx()
 @param[in]	name		Table name, format: "db/table_name".
 @param[in]	form		Table format; columns and index information.
 @param[in]	create_info	Create info (including create statement string).
+@param[in]	file_per_table	whether to create .ibd file
+@param[in,out]	trx		dictionary transaction, or NULL to create new
 @return	0 if success else error number. */
-int
+inline int
 ha_innobase::create(
 	const char*	name,
 	TABLE*		form,
-	HA_CREATE_INFO*	create_info)
+	HA_CREATE_INFO*	create_info,
+	bool		file_per_table,
+	trx_t*		trx)
 {
 	int		error;
 	char		norm_name[FN_REFLEN];	/* {database}/{tablename} */
 	char		remote_path[FN_REFLEN];	/* Absolute path of table */
-	trx_t*		trx;
+
 	DBUG_ENTER("ha_innobase::create");
 
 	create_table_info_t	info(ha_thd(),
 				     form,
 				     create_info,
 				     norm_name,
-				     remote_path);
+				     remote_path,
+				     file_per_table, trx);
 
 	/* Initialize the object. */
 	if ((error = info.initialize())) {
@@ -13055,9 +13058,11 @@ ha_innobase::create(
 		DBUG_RETURN(error);
 	}
 
-	info.allocate_trx();
-
-	trx = info.trx();
+	bool own_trx = !trx;
+	if (own_trx) {
+		info.allocate_trx();
+		trx = info.trx();
+	}
 
 	/* Latch the InnoDB data dictionary exclusively so that no deadlocks
 	or lock waits can happen in it during a table create operation.
@@ -13065,10 +13070,16 @@ ha_innobase::create(
 	row_mysql_lock_data_dictionary(trx);
 
 	if ((error = info.create_table())) {
-		goto cleanup;
+		if (own_trx) {
+			trx_rollback_for_mysql(trx);
+		}
+		row_mysql_unlock_data_dictionary(trx);
+		goto func_exit;
 	}
 
-	innobase_commit_low(trx);
+	if (own_trx) {
+		innobase_commit_low(trx);
+	}
 
 	ut_ad(!srv_read_only_mode);
 	row_mysql_unlock_data_dictionary(trx);
@@ -13083,17 +13094,26 @@ ha_innobase::create(
 	utility threads: */
 
 	srv_active_wake_master_thread();
-
-	trx_free_for_mysql(trx);
+func_exit:
+	if (own_trx) {
+		trx_free_for_mysql(trx);
+	}
 
 	DBUG_RETURN(error);
+}
 
-cleanup:
-	trx_rollback_for_mysql(trx);
-	row_mysql_unlock_data_dictionary(trx);
-	trx_free_for_mysql(trx);
-
-	DBUG_RETURN(error);
+/** Create a new table to an InnoDB database.
+@param[in]	name		Table name, format: "db/table_name".
+@param[in]	form		Table format; columns and index information.
+@param[in]	create_info	Create info (including create statement string).
+@return	0 if success else error number. */
+int
+ha_innobase::create(
+	const char*	name,
+	TABLE*		form,
+	HA_CREATE_INFO*	create_info)
+{
+	return create(name, form, create_info, srv_file_per_table);
 }
 
 /*****************************************************************//**
@@ -13216,72 +13236,16 @@ ha_innobase::discard_or_import_tablespace(
 	DBUG_RETURN(convert_error_code_to_mysql(err, dict_table->flags, NULL));
 }
 
-/*****************************************************************//**
-Deletes all rows of an InnoDB table.
-@return error number */
-
-int
-ha_innobase::truncate()
-/*===================*/
-{
-	DBUG_ENTER("ha_innobase::truncate");
-
-	if (high_level_read_only) {
-		DBUG_RETURN(HA_ERR_TABLE_READONLY);
-	}
-
-	/* Get the transaction associated with the current thd, or create one
-	if not yet created, and update m_prebuilt->trx */
-
-	update_thd(ha_thd());
-
-	if (!trx_is_started(m_prebuilt->trx)) {
-		++m_prebuilt->trx->will_lock;
-	}
-
-	dberr_t	err;
-
-	/* Truncate the table in InnoDB */
-	err = row_truncate_table_for_mysql(m_prebuilt->table, m_prebuilt->trx);
-
-	int	error;
-
-	switch (err) {
-	case DB_TABLESPACE_DELETED:
-	case DB_TABLESPACE_NOT_FOUND:
-		ib_senderrf(
-			m_prebuilt->trx->mysql_thd, IB_LOG_LEVEL_ERROR,
-			(err == DB_TABLESPACE_DELETED ?
-			ER_TABLESPACE_DISCARDED : ER_TABLESPACE_MISSING),
-			table->s->table_name.str);
-		table->status = STATUS_NOT_FOUND;
-		error = HA_ERR_TABLESPACE_MISSING;
-		break;
-
-	default:
-		error = convert_error_code_to_mysql(
-			err, m_prebuilt->table->flags,
-			m_prebuilt->trx->mysql_thd);
-
-		table->status = STATUS_NOT_FOUND;
-		break;
-	}
-
-	DBUG_RETURN(error);
-}
-
-/*****************************************************************//**
+/**
 Drops a table from an InnoDB database. Before calling this function,
 MySQL calls innobase_commit to commit the transaction of the current user.
 Then the current user cannot have locks set on the table. Drop table
 operation inside InnoDB will remove all locks any user has on the table
 inside InnoDB.
+@param[in]	name	table name
+@param[in]	sqlcom	SQLCOM_DROP_DB, SQLCOM_TRUNCATE, ...
 @return error number */
-
-int
-ha_innobase::delete_table(
-/*======================*/
-	const char*	name)	/*!< in: table name */
+inline int ha_innobase::delete_table(const char* name, enum_sql_command sqlcom)
 {
 	dberr_t	err;
 	THD*	thd = ha_thd();
@@ -13345,9 +13309,7 @@ ha_innobase::delete_table(
 
 	/* Drop the table in InnoDB */
 
-	err = row_drop_table_for_mysql(
-		norm_name, trx, thd_sql_command(thd) == SQLCOM_DROP_DB,
-		false);
+	err = row_drop_table_for_mysql(norm_name, trx, sqlcom, false);
 
 	if (err == DB_TABLE_NOT_FOUND
 	    && innobase_get_lower_case_table_names() == 1) {
@@ -13371,9 +13333,7 @@ ha_innobase::delete_table(
 				par_case_name, name, FALSE);
 #endif
 			err = row_drop_table_for_mysql(
-				par_case_name, trx,
-				thd_sql_command(thd) == SQLCOM_DROP_DB,
-				FALSE);
+				par_case_name, trx, sqlcom, false);
 		}
 	}
 
@@ -13436,9 +13396,7 @@ ha_innobase::delete_table(
 				par_case_name, name, FALSE);
 #endif /* _WIN32 */
 			err = row_drop_table_for_mysql(
-				par_case_name, trx,
-				thd_sql_command(thd) == SQLCOM_DROP_DB,
-				true);
+				par_case_name, trx, sqlcom, true);
 		}
 	}
 
@@ -13456,6 +13414,25 @@ ha_innobase::delete_table(
 	DBUG_RETURN(convert_error_code_to_mysql(err, 0, NULL));
 }
 
+/** Drop an InnoDB table.
+@param[in]	name	table name
+@return error number */
+int ha_innobase::delete_table(const char* name)
+{
+	enum_sql_command sqlcom = enum_sql_command(thd_sql_command(ha_thd()));
+
+        if (sqlcom == SQLCOM_TRUNCATE
+            && thd_killed(ha_thd())
+            && (m_prebuilt == NULL
+                || dict_table_is_temporary(m_prebuilt->table))) {
+                sqlcom = SQLCOM_DROP_TABLE;
+        }
+
+	/* SQLCOM_TRUNCATE will be passed via ha_innobase::truncate() only. */
+        DBUG_ASSERT(sqlcom != SQLCOM_TRUNCATE);
+        return delete_table(name, sqlcom);
+}
+
 /** Remove all tables in the named database inside InnoDB.
 @param[in]	hton	handlerton from InnoDB
 @param[in]	path	Database path; Inside InnoDB the name of the last
@@ -13530,11 +13507,10 @@ innobase_drop_database(
 /*********************************************************************//**
 Renames an InnoDB table.
 @return DB_SUCCESS or error code */
-inline MY_ATTRIBUTE((warn_unused_result))
+inline
 dberr_t
 innobase_rename_table(
 /*==================*/
-	THD*            thd,    /*!< Connection thread handle */
 	trx_t*		trx,	/*!< in: transaction */
 	const char*	from,	/*!< in: old name of the table */
 	const char*	to)	/*!< in: new name of the table */
@@ -13544,7 +13520,8 @@ innobase_rename_table(
 	char	norm_from[FN_REFLEN];
 
 	DBUG_ENTER("innobase_rename_table");
-	DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX);
+	DBUG_ASSERT(trx_get_dict_operation(trx) == TRX_DICT_OP_INDEX
+		    || trx_get_dict_operation(trx) == TRX_DICT_OP_TABLE);
 
 	ut_ad(!srv_read_only_mode);
 
@@ -13565,7 +13542,7 @@ innobase_rename_table(
 
 	/* Since DICT_BG_YIELD has sleep for 250 milliseconds,
 	Convert lock_wait_timeout unit from second to 250 milliseconds */
-	long int lock_wait_timeout = thd_lock_wait_timeout(thd) * 4;
+	long int lock_wait_timeout = thd_lock_wait_timeout(trx->mysql_thd) * 4;
 	if (table != NULL) {
 		for (dict_index_t* index = dict_table_get_first_index(table);
 		     index != NULL;
@@ -13655,6 +13632,74 @@ innobase_rename_table(
 	DBUG_RETURN(error);
 }
 
+/** TRUNCATE TABLE
+@return	error code
+@retval	0	on success */
+int ha_innobase::truncate()
+{
+	DBUG_ENTER("ha_innobase::truncate");
+
+	if (high_level_read_only) {
+		DBUG_RETURN(HA_ERR_TABLE_READONLY);
+	}
+
+	update_thd();
+
+	HA_CREATE_INFO	info;
+	mem_heap_t*	heap = mem_heap_create(1000);
+	dict_table_t*	ib_table = m_prebuilt->table;
+	memset(&info, 0, sizeof info);
+	update_create_info_from_table(&info, table);
+
+	if (dict_table_is_temporary(ib_table)) {
+		info.options|= HA_LEX_CREATE_TMP_TABLE;
+	} else {
+		dict_get_and_save_data_dir_path(ib_table, false);
+	}
+
+	char* data_file_name = ib_table->data_dir_path;
+
+	if (data_file_name) {
+		info.data_file_name = data_file_name
+			= mem_heap_strdup(heap, data_file_name);
+	}
+
+	const char* temp_name = dict_mem_create_temporary_tablename(
+		heap, ib_table->name.m_name, ib_table->id);
+	trx_t*	trx = innobase_trx_allocate(m_user_thd);
+
+	++trx->will_lock;
+	trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
+	int err = convert_error_code_to_mysql(
+		innobase_rename_table(trx, ib_table->name.m_name, temp_name),
+		ib_table->flags, m_user_thd);
+	if (!err) {
+		err = create(m_share->table_name, table, &info,
+			     dict_table_is_file_per_table(ib_table), trx);
+	}
+
+	if (err) {
+#if MYSQL_VERSION_ID < 100303 /* MariaDB 10.3 does full rollback for RENAME */
+		innobase_rename_table(trx, temp_name, ib_table->name.m_name);
+#endif
+		trx_rollback_to_savepoint(trx, NULL);
+	}
+
+	innobase_commit_low(trx);
+	trx_free_for_mysql(trx);
+
+	if (!err) {
+		/* Reopen the newly created table, and drop the
+		original table that was renamed to temp_name. */
+		close();
+		open(m_share->table_name, 0, 0);
+		delete_table(temp_name, SQLCOM_TRUNCATE);
+	}
+
+	mem_heap_free(heap);
+	DBUG_RETURN(err);
+}
+
 /*********************************************************************//**
 Renames an InnoDB table.
 @return 0 or error code */
@@ -13680,7 +13725,7 @@ ha_innobase::rename_table(
 	++trx->will_lock;
 	trx_set_dict_operation(trx, TRX_DICT_OP_INDEX);
 
-	dberr_t	error = innobase_rename_table(thd, trx, from, to);
+	dberr_t	error = innobase_rename_table(trx, from, to);
 
 	DEBUG_SYNC(thd, "after_innobase_rename_table");
 
diff --git a/storage/innobase/handler/ha_innodb.h b/storage/innobase/handler/ha_innodb.h
index 1a47dab423f..42b15046dfe 100644
--- a/storage/innobase/handler/ha_innodb.h
+++ b/storage/innobase/handler/ha_innodb.h
@@ -55,6 +55,9 @@ typedef struct st_innobase_share {
 /** Prebuilt structures in an InnoDB table handle used within MySQL */
 struct row_prebuilt_t;
 
+/** InnoDB transaction */
+struct trx_t;
+
 /** Engine specific table options are defined using this struct */
 struct ha_table_option_struct
 {
@@ -225,6 +228,13 @@ class ha_innobase: public handler
 
 	void update_create_info(HA_CREATE_INFO* create_info);
 
+	inline int create(
+		const char*		name,
+		TABLE*			form,
+		HA_CREATE_INFO*		create_info,
+		bool			file_per_table,
+		trx_t*			trx = NULL);
+
 	int create(
 		const char*		name,
 		TABLE*			form,
@@ -233,6 +243,8 @@ class ha_innobase: public handler
 	const char* check_table_options(THD *thd, TABLE* table,
 		HA_CREATE_INFO*	create_info, const bool use_tablespace, const ulint file_format);
 
+	inline int delete_table(const char* name, enum_sql_command sqlcom);
+
 	int truncate();
 
 	int delete_table(const char *name);
@@ -684,13 +696,16 @@ class create_table_info_t
 		TABLE*		form,
 		HA_CREATE_INFO*	create_info,
 		char*		table_name,
-		char*		remote_path)
+		char*		remote_path,
+		bool		file_per_table,
+		trx_t*		trx = NULL)
 	:m_thd(thd),
+	m_trx(trx),
 	m_form(form),
 	m_create_info(create_info),
 	m_table_name(table_name),
 	m_remote_path(remote_path),
-	m_innodb_file_per_table(srv_file_per_table)
+	m_innodb_file_per_table(file_per_table)
 	{}
 
 	/** Initialize the object. */
diff --git a/storage/innobase/handler/handler0alter.cc b/storage/innobase/handler/handler0alter.cc
index 6e318a040ca..3dd92ba7807 100644
--- a/storage/innobase/handler/handler0alter.cc
+++ b/storage/innobase/handler/handler0alter.cc
@@ -5579,7 +5579,8 @@ ha_innobase::prepare_inplace_alter_table(
 				     altered_table,
 				     ha_alter_info->create_info,
 				     NULL,
-				     NULL);
+				     NULL,
+				     srv_file_per_table);
 
 	info.set_tablespace_type(indexed_table->space != TRX_SYS_SPACE);
 
diff --git a/storage/innobase/include/fil0fil.h b/storage/innobase/include/fil0fil.h
index 8aa8a746ce1..9f83d030f43 100644
--- a/storage/innobase/include/fil0fil.h
+++ b/storage/innobase/include/fil0fil.h
@@ -101,10 +101,8 @@ struct fil_space_t {
 				new write operations because we don't
 				check this flag when doing flush
 				batches. */
+	/** whether undo tablespace truncation is in progress */
 	bool		is_being_truncated;
-				/*!< this is set to true when we prepare to
-				truncate a single-table tablespace and its
-				.ibd file */
 #ifdef UNIV_DEBUG
 	ulint		redo_skipped_count;
 				/*!< reference count for operations who want
@@ -188,12 +186,8 @@ struct fil_space_t {
 
 	ulint		magic_n;/*!< FIL_SPACE_MAGIC_N */
 
-	/** @return whether the tablespace is about to be dropped or
-	truncated */
-	bool is_stopping() const
-	{
-		return stop_new_ops || is_being_truncated;
-	}
+	/** @return whether the tablespace is about to be dropped */
+	bool is_stopping() const { return stop_new_ops;	}
 
 	/** @return whether doublewrite buffering is needed */
 	bool use_doublewrite() const
@@ -941,36 +935,15 @@ fil_delete_tablespace(
 #endif /* BTR_CUR_HASH_ADAPT */
 	);
 
-/** Truncate the tablespace to needed size.
-@param[in]	space_id	id of tablespace to truncate
-@param[in]	size_in_pages	truncate size.
-@return true if truncate was successful. */
-bool
-fil_truncate_tablespace(
-	ulint		space_id,
-	ulint		size_in_pages);
-
-/*******************************************************************//**
-Prepare for truncating a single-table tablespace. The tablespace
-must be cached in the memory cache.
-1) Check pending operations on a tablespace;
-2) Remove all insert buffer entries for the tablespace;
-@return DB_SUCCESS or error */
-dberr_t
-fil_prepare_for_truncate(
-/*=====================*/
-	ulint	id);			/*!< in: space id */
+/** Prepare to truncate a tablespace.
+@param[in]	space_id	tablespace id
+@return	the tablespace
+@retval	NULL if the tablespace does not exist */
+fil_space_t* fil_truncate_prepare(ulint space_id);
 
-/** Reinitialize the original tablespace header with the same space id
-for single tablespace
-@param[in]	table		table belongs to the tablespace
-@param[in]	size            size in blocks
-@param[in]	trx		Transaction covering truncate */
-void
-fil_reinit_space_header_for_table(
-	dict_table_t*	table,
-	ulint		size,
-	trx_t*		trx);
+/** Write log about a truncate operation. */
+void fil_truncate_log(fil_space_t* space, ulint size, mtr_t* mtr)
+	MY_ATTRIBUTE((nonnull));
 
 /*******************************************************************//**
 Closes a single-table tablespace. The tablespace must be cached in the
diff --git a/storage/innobase/include/row0mysql.h b/storage/innobase/include/row0mysql.h
index 8a573a23652..32aa7dd8d30 100644
--- a/storage/innobase/include/row0mysql.h
+++ b/storage/innobase/include/row0mysql.h
@@ -29,6 +29,8 @@ Created 9/17/2000 Heikki Tuuri
 #define row0mysql_h
 
 #include "ha_prototypes.h"
+#include "sql_list.h"
+#include "sql_cmd.h"
 
 #include "data0data.h"
 #include "que0types.h"
@@ -434,32 +436,28 @@ row_mysql_lock_table(
 	const char*	op_info)	/*!< in: string for trx->op_info */
 	MY_ATTRIBUTE((nonnull, warn_unused_result));
 
-/*********************************************************************//**
-Truncates a table for MySQL.
-@return error code or DB_SUCCESS */
-dberr_t
-row_truncate_table_for_mysql(
-/*=========================*/
-	dict_table_t*	table,	/*!< in: table handle */
-	trx_t*		trx)	/*!< in: transaction handle */
-	MY_ATTRIBUTE((nonnull, warn_unused_result));
-/*********************************************************************//**
-Drops a table for MySQL.  If the data dictionary was not already locked
-by the transaction, the transaction will be committed.  Otherwise, the
-data dictionary will remain locked.
-@return error code or DB_SUCCESS */
+/** Drop a table.
+If the data dictionary was not already locked by the transaction,
+the transaction will be committed.  Otherwise, the data dictionary
+will remain locked.
+@param[in]	name		Table name
+@param[in,out]	trx		Transaction handle
+@param[in]	sqlcom		type of SQL operation
+@param[in]	create_failed	true=create table failed
+				because e.g. foreign key column
+@param[in]	nonatomic	Whether it is permitted to release
+				and reacquire dict_operation_lock
+@return error code */
 dberr_t
 row_drop_table_for_mysql(
-/*=====================*/
-	const char*	name,	/*!< in: table name */
-	trx_t*		trx,	/*!< in: dictionary transaction handle */
-	bool		drop_db,/*!< in: true=dropping whole database */
-	ibool		create_failed,/*!<in: TRUE=create table failed
-					because e.g. foreign key column
-					type mismatch. */
-	bool		nonatomic = true);
-				/*!< in: whether it is permitted
-				to release and reacquire dict_operation_lock */
+	const char*		name,
+	trx_t*			trx,
+	enum_sql_command	sqlcom,
+	ibool			create_failed,
+	bool			nonatomic = true);
+
+/** Drop a table after failed CREATE TABLE. */
+dberr_t row_drop_table_after_create_fail(const char* name, trx_t* trx);
 
 /*********************************************************************//**
 Discards the tablespace of a table which stored in an .ibd file. Discarding
diff --git a/storage/innobase/include/row0trunc.h b/storage/innobase/include/row0trunc.h
index 56302a0e570..f9a20665a3b 100644
--- a/storage/innobase/include/row0trunc.h
+++ b/storage/innobase/include/row0trunc.h
@@ -1,6 +1,7 @@
 /*****************************************************************************
 
 Copyright (c) 2013, 2015, Oracle and/or its affiliates. All Rights Reserved.
+Copyright (c) 2018, MariaDB Corporation.
 
 This program is free software; you can redistribute it and/or modify it under
 the terms of the GNU General Public License as published by the Free Software
@@ -420,14 +421,4 @@ class TruncateLogParser {
 		const char*		log_file_name);
 };
 
-
-/**
-Truncates a table for MySQL.
-@param table		table being truncated
-@param trx		transaction covering the truncate
-@return	error code or DB_SUCCESS */
-dberr_t
-row_truncate_table_for_mysql(dict_table_t* table, trx_t* trx);
-
 #endif /* row0trunc_h */
-
diff --git a/storage/innobase/log/log0recv.cc b/storage/innobase/log/log0recv.cc
index c8976b193e2..2511dbd00c5 100644
--- a/storage/innobase/log/log0recv.cc
+++ b/storage/innobase/log/log0recv.cc
@@ -384,6 +384,13 @@ fil_name_parse(
 
 		break;
 	case MLOG_FILE_CREATE2:
+		if (first_page_no == 0) {
+			break;
+		}
+		ut_ad(first_page_no == SRV_UNDO_TABLESPACE_SIZE_IN_PAGES);
+		ut_ad(srv_is_undo_tablespace(space_id));
+		/* TODO: discard any logs for (space_id,first_page_no+)
+		before the current LSN */
 		break;
 	case MLOG_FILE_RENAME2:
 		if (corrupt) {
diff --git a/storage/innobase/row/row0merge.cc b/storage/innobase/row/row0merge.cc
index 951c16394a7..5ea8f77308e 100644
--- a/storage/innobase/row/row0merge.cc
+++ b/storage/innobase/row/row0merge.cc
@@ -4486,7 +4486,7 @@ row_merge_drop_table(
 	ut_a(table->get_ref_count() == 0);
 
 	return(row_drop_table_for_mysql(table->name.m_name,
-			trx, false, false, false));
+			trx, SQLCOM_DROP_TABLE, false, false));
 }
 
 /** Write an MLOG_INDEX_LOAD record to indicate in the redo-log
diff --git a/storage/innobase/row/row0mysql.cc b/storage/innobase/row/row0mysql.cc
index 5ba8d038671..93334e4f969 100644
--- a/storage/innobase/row/row0mysql.cc
+++ b/storage/innobase/row/row0mysql.cc
@@ -2499,7 +2499,8 @@ row_create_index_for_mysql(
 			trx_rollback_to_savepoint(trx, NULL);
 		}
 
-		row_drop_table_for_mysql(table_name, trx, FALSE, true);
+		row_drop_table_for_mysql(table_name, trx, SQLCOM_DROP_TABLE,
+					 true);
 
 		if (trx_is_started(trx)) {
 
@@ -2591,7 +2592,7 @@ row_table_add_foreign_constraints(
 			trx_rollback_to_savepoint(trx, NULL);
 		}
 
-		row_drop_table_for_mysql(name, trx, FALSE, true);
+		row_drop_table_for_mysql(name, trx, SQLCOM_DROP_TABLE, true);
 
 		if (trx_is_started(trx)) {
 
@@ -2631,7 +2632,7 @@ row_drop_table_for_mysql_in_background(
 
 	/* Try to drop the table in InnoDB */
 
-	error = row_drop_table_for_mysql(name, trx, FALSE, FALSE);
+	error = row_drop_table_for_mysql(name, trx, SQLCOM_TRUNCATE, false);
 
 	/* Flush the log to reduce probability that the .frm files and
 	the InnoDB data dictionary get out-of-sync if the user runs
@@ -3319,25 +3320,25 @@ row_drop_single_table_tablespace(
 	return(err);
 }
 
-/** Drop a table for MySQL.
+/** Drop a table.
 If the data dictionary was not already locked by the transaction,
 the transaction will be committed.  Otherwise, the data dictionary
 will remain locked.
 @param[in]	name		Table name
-@param[in]	trx		Transaction handle
-@param[in]	drop_db		true=dropping whole database
-@param[in]	create_failed	TRUE=create table failed
+@param[in,out]	trx		Transaction handle
+@param[in]	sqlcom		type of SQL operation
+@param[in]	create_failed	true=create table failed
 				because e.g. foreign key column
 @param[in]	nonatomic	Whether it is permitted to release
 				and reacquire dict_operation_lock
 @return error code or DB_SUCCESS */
 dberr_t
 row_drop_table_for_mysql(
-	const char*	name,
-	trx_t*		trx,
-	bool		drop_db,
-	ibool		create_failed,
-	bool		nonatomic)
+	const char*		name,
+	trx_t*			trx,
+	enum_sql_command	sqlcom,
+	ibool			create_failed,
+	bool			nonatomic)
 {
 	dberr_t		err;
 	dict_foreign_t*	foreign;
@@ -3498,7 +3499,7 @@ row_drop_table_for_mysql(
 
 			foreign = *it;
 
-			const bool	ref_ok = drop_db
+			const bool	ref_ok = sqlcom == SQLCOM_DROP_DB
 				&& dict_tables_have_same_db(
 					name,
 					foreign->foreign_table_name_lookup);
@@ -3535,7 +3536,6 @@ row_drop_table_for_mysql(
 		}
 	}
 
-
 	DBUG_EXECUTE_IF("row_drop_table_add_to_background",
 		row_add_table_to_background_drop_list(table->id);
 		err = DB_SUCCESS;
@@ -3668,12 +3668,11 @@ row_drop_table_for_mysql(
 
 		pars_info_add_str_literal(info, "table_name", name);
 
-		err = que_eval_sql(
+		err = (sqlcom == SQLCOM_TRUNCATE) ? DB_SUCCESS : que_eval_sql(
 			info,
-			"PROCEDURE DROP_TABLE_PROC () IS\n"
+			"PROCEDURE DROP_FOREIGN_PROC () IS\n"
 			"sys_foreign_id CHAR;\n"
 			"table_id CHAR;\n"
-			"index_id CHAR;\n"
 			"foreign_id CHAR;\n"
 			"space_id INT;\n"
 			"found INT;\n"
@@ -3685,11 +3684,6 @@ row_drop_table_for_mysql(
 			"  = TO_BINARY(:table_name)\n"
 			"LOCK IN SHARE MODE;\n"
 
-			"DECLARE CURSOR cur_idx IS\n"
-			"SELECT ID FROM SYS_INDEXES\n"
-			"WHERE TABLE_ID = table_id\n"
-			"LOCK IN SHARE MODE;\n"
-
 			"BEGIN\n"
 
 			"SELECT ID INTO table_id\n"
@@ -3738,21 +3732,35 @@ row_drop_table_for_mysql(
 			"END LOOP;\n"
 			"CLOSE cur_fk;\n"
 
-			"found := 1;\n"
-			"OPEN cur_idx;\n"
-			"WHILE found = 1 LOOP\n"
-			"       FETCH cur_idx INTO index_id;\n"
-			"       IF (SQL % NOTFOUND) THEN\n"
-			"               found := 0;\n"
-			"       ELSE\n"
-			"               DELETE FROM SYS_FIELDS\n"
-			"               WHERE INDEX_ID = index_id;\n"
-			"               DELETE FROM SYS_INDEXES\n"
-			"               WHERE ID = index_id\n"
-			"               AND TABLE_ID = table_id;\n"
-			"       END IF;\n"
-			"END LOOP;\n"
-			"CLOSE cur_idx;\n"
+			"END;\n",
+			FALSE, trx);
+
+		if (err == DB_SUCCESS) {
+			if (sqlcom != SQLCOM_TRUNCATE) {
+				info = pars_info_create();
+				pars_info_add_str_literal(info, "table_name",
+							  name);
+			}
+
+			err = que_eval_sql(
+			info,
+			"PROCEDURE DROP_TABLE_PROC () IS\n"
+			"table_id CHAR;\n"
+			"space_id INT;\n"
+			"index_id CHAR;\n"
+
+			"DECLARE CURSOR cur_idx IS\n"
+			"SELECT ID FROM SYS_INDEXES\n"
+			"WHERE TABLE_ID = table_id\n"
+			"FOR UPDATE;\n"
+
+			"BEGIN\n"
+			"SELECT ID, SPACE INTO table_id,space_id\n"
+			"FROM SYS_TABLES\n"
+			"WHERE NAME = :table_name FOR UPDATE;\n"
+			"IF (SQL % NOTFOUND) THEN\n"
+			"       RETURN;\n"
+			"END IF;\n"
 
 			"DELETE FROM SYS_COLUMNS\n"
 			"WHERE TABLE_ID = table_id;\n"
@@ -3766,8 +3774,25 @@ row_drop_table_for_mysql(
 
 			"DELETE FROM SYS_VIRTUAL\n"
 			"WHERE TABLE_ID = table_id;\n"
+
+			"OPEN cur_idx;\n"
+			"WHILE 1 = 1 LOOP\n"
+			"       FETCH cur_idx INTO index_id;\n"
+			"       IF (SQL % NOTFOUND) THEN\n"
+			"		EXIT;\n"
+			"       ELSE\n"
+			"               DELETE FROM SYS_FIELDS\n"
+			"               WHERE INDEX_ID = index_id;\n"
+			"               DELETE FROM SYS_INDEXES\n"
+			"               WHERE ID = index_id\n"
+			"               AND TABLE_ID = table_id;\n"
+			"       END IF;\n"
+			"END LOOP;\n"
+			"CLOSE cur_idx;\n"
+
 			"END;\n",
 			FALSE, trx);
+		}
 	} else {
 		page_no = page_nos;
 		for (dict_index_t* index = dict_table_get_first_index(table);
@@ -3905,6 +3930,13 @@ row_drop_table_for_mysql(
 	DBUG_RETURN(err);
 }
 
+/** Drop a table after failed CREATE TABLE. */
+dberr_t row_drop_table_after_create_fail(const char* name, trx_t* trx)
+{
+	ib::warn() << "Dropping incompletely created " << name << " table.";
+	return row_drop_table_for_mysql(name, trx, SQLCOM_DROP_DB, true);
+}
+
 /*******************************************************************//**
 Drop all foreign keys in a database, see Bug#18942.
 Called at the end of row_drop_database_for_mysql().
@@ -4093,7 +4125,8 @@ row_drop_database_for_mysql(
 			goto loop;
 		}
 
-		err = row_drop_table_for_mysql(table_name, trx, TRUE, FALSE);
+		err = row_drop_table_for_mysql(
+			table_name, trx, SQLCOM_DROP_DB, false);
 		trx_commit_for_mysql(trx);
 
 		if (err != DB_SUCCESS) {
diff --git a/storage/innobase/row/row0trunc.cc b/storage/innobase/row/row0trunc.cc
index 79870ceaf5f..dd96d84d075 100644
--- a/storage/innobase/row/row0trunc.cc
+++ b/storage/innobase/row/row0trunc.cc
@@ -240,335 +240,6 @@ class Callback
 	const bool		m_noredo;
 };
 
-/**
-Creates a TRUNCATE log record with space id, table name, data directory path,
-tablespace flags, table format, index ids, index types, number of index fields
-and index field information of the table. */
-class TruncateLogger : public Callback {
-
-public:
-	/**
-	Constructor
-
-	@param table	Table to truncate
-	@param flags	tablespace falgs */
-	TruncateLogger(
-		dict_table_t*	table,
-		ulint		flags,
-		table_id_t	new_table_id)
-		:
-		Callback(table->id, false),
-		m_table(table),
-		m_flags(flags),
-		m_truncate(table->id, new_table_id, table->data_dir_path),
-		m_log_file_name()
-	{
-		/* Do nothing */
-	}
-
-	/**
-	Initialize Truncate Logger by constructing Truncate Log File Name.
-
-	@return DB_SUCCESS or error code. */
-	dberr_t init()
-	{
-		/* Construct log file name. */
-		ulint	log_file_name_buf_sz =
-			strlen(srv_log_group_home_dir) + 22 + 22 + 1 /* NUL */
-			+ strlen(TruncateLogger::s_log_prefix)
-			+ strlen(TruncateLogger::s_log_ext);
-
-		m_log_file_name = UT_NEW_ARRAY_NOKEY(char, log_file_name_buf_sz);
-		if (m_log_file_name == NULL) {
-			return(DB_OUT_OF_MEMORY);
-		}
-		memset(m_log_file_name, 0, log_file_name_buf_sz);
-
-		strcpy(m_log_file_name, srv_log_group_home_dir);
-		ulint	log_file_name_len = strlen(m_log_file_name);
-		if (m_log_file_name[log_file_name_len - 1]
-			!= OS_PATH_SEPARATOR) {
-
-			m_log_file_name[log_file_name_len]
-				= OS_PATH_SEPARATOR;
-			log_file_name_len = strlen(m_log_file_name);
-		}
-
-		snprintf(m_log_file_name + log_file_name_len,
-			 log_file_name_buf_sz - log_file_name_len,
-			 "%s%lu_%lu_%s",
-			 TruncateLogger::s_log_prefix,
-			 (ulong) m_table->space,
-			 (ulong) m_table->id,
-			 TruncateLogger::s_log_ext);
-
-		return(DB_SUCCESS);
-
-	}
-
-	/**
-	Destructor */
-	~TruncateLogger()
-	{
-		if (m_log_file_name != NULL) {
-			bool exist;
-			os_file_delete_if_exists(
-				innodb_log_file_key, m_log_file_name, &exist);
-			UT_DELETE_ARRAY(m_log_file_name);
-			m_log_file_name = NULL;
-		}
-	}
-
-	/**
-	@param mtr	mini-transaction covering the read
-	@param pcur	persistent cursor used for reading
-	@return DB_SUCCESS or error code */
-	dberr_t operator()(mtr_t* mtr, btr_pcur_t* pcur);
-
-	/** Called after iteratoring over the records.
-	@return true if invariant satisfied. */
-	bool debug() const
-	{
-		/* We must find all the index entries on disk. */
-		return(UT_LIST_GET_LEN(m_table->indexes)
-		       == m_truncate.indexes());
-	}
-
-	/**
-	Write the TRUNCATE log
-	@return DB_SUCCESS or error code */
-	dberr_t log() const
-	{
-		dberr_t	err = DB_SUCCESS;
-
-		if (m_log_file_name == 0) {
-			return(DB_ERROR);
-		}
-
-		bool		ret;
-		os_file_t	handle = os_file_create(
-			innodb_log_file_key, m_log_file_name,
-			OS_FILE_CREATE, OS_FILE_NORMAL,
-			OS_LOG_FILE, srv_read_only_mode, &ret);
-		if (!ret) {
-			return(DB_IO_ERROR);
-		}
-
-
-		ulint	sz = UNIV_PAGE_SIZE;
-		void*	buf = ut_zalloc_nokey(sz + UNIV_PAGE_SIZE);
-		if (buf == 0) {
-			os_file_close(handle);
-			return(DB_OUT_OF_MEMORY);
-		}
-
-		/* Align the memory for file i/o if we might have O_DIRECT set*/
-		byte*	log_buf = static_cast<byte*>(
-			ut_align(buf, UNIV_PAGE_SIZE));
-
-		lsn_t	lsn = log_get_lsn();
-
-		/* Generally loop should exit in single go but
-		just for those 1% of rare cases we need to assume
-		corner case. */
-		do {
-			/* First 4 bytes are reserved for magic number
-			which is currently 0. */
-			err = m_truncate.write(
-				log_buf + 4, log_buf + sz - 4,
-				m_table->space, m_table->name.m_name,
-				m_flags, m_table->flags, lsn);
-
-			DBUG_EXECUTE_IF("ib_err_trunc_oom_logging",
-					err = DB_FAIL;);
-
-			if (err != DB_SUCCESS) {
-				ut_ad(err == DB_FAIL);
-				ut_free(buf);
-				sz *= 2;
-				buf = ut_zalloc_nokey(sz + UNIV_PAGE_SIZE);
-				DBUG_EXECUTE_IF("ib_err_trunc_oom_logging",
-						ut_free(buf);
-						buf = 0;);
-				if (buf == 0) {
-					os_file_close(handle);
-					return(DB_OUT_OF_MEMORY);
-				}
-				log_buf = static_cast<byte*>(
-					ut_align(buf, UNIV_PAGE_SIZE));
-			}
-
-		} while (err != DB_SUCCESS);
-
-		dberr_t	io_err;
-
-		IORequest	request(IORequest::WRITE);
-
-		io_err = os_file_write(
-			request, m_log_file_name, handle, log_buf, 0, sz);
-
-		if (io_err != DB_SUCCESS) {
-
-			ib::error()
-				<< "IO: Failed to write the file size to '"
-				<< m_log_file_name << "'";
-
-			/* Preserve the original error code */
-			if (err == DB_SUCCESS) {
-				err = io_err;
-			}
-		}
-
-		os_file_flush(handle);
-		os_file_close(handle);
-
-		ut_free(buf);
-
-		/* Why we need MLOG_TRUNCATE when we have truncate_log for
-		recovery?
-		- truncate log can protect us if crash happens while truncate
-		  is active. Once truncate is done truncate log is removed.
-		- If crash happens post truncate and system is yet to
-		  checkpoint, on recovery we would see REDO records from action
-		  before truncate (unless we explicitly checkpoint before
-		  returning from truncate API. Costly alternative so rejected).
-		- These REDO records may reference a page that doesn't exist
-		  post truncate so we need a mechanism to skip all such REDO
-		  records. MLOG_TRUNCATE records space_id and lsn that exactly
-		  serve the purpose.
-		- If checkpoint happens post truncate and crash happens post
-		  this point then neither MLOG_TRUNCATE nor REDO record
-		  from action before truncate are accessible. */
-		if (!is_system_tablespace(m_table->space)) {
-			mtr_t	mtr;
-			byte*	log_ptr;
-
-			mtr_start(&mtr);
-
-			log_ptr = mlog_open(&mtr, 11 + 8);
-			log_ptr = mlog_write_initial_log_record_low(
-				MLOG_TRUNCATE, m_table->space, 0,
-				log_ptr, &mtr);
-
-			mach_write_to_8(log_ptr, lsn);
-			log_ptr += 8;
-
-			mlog_close(&mtr, log_ptr);
-			mtr_commit(&mtr);
-		}
-
-		return(err);
-	}
-
-	/**
-	Indicate completion of truncate log by writing magic-number.
-	File will be removed from the system but to protect against
-	unlink (File-System) anomalies we ensure we write magic-number. */
-	void done()
-	{
-		if (m_log_file_name == 0) {
-			return;
-		}
-
-		bool	ret;
-		os_file_t handle = os_file_create_simple_no_error_handling(
-			innodb_log_file_key, m_log_file_name,
-			OS_FILE_OPEN, OS_FILE_READ_WRITE,
-			srv_read_only_mode, &ret);
-		DBUG_EXECUTE_IF("ib_err_trunc_writing_magic_number",
-				os_file_close(handle);
-				ret = false;);
-		if (!ret) {
-			ib::error() << "Failed to open truncate log file "
-				<< m_log_file_name << "."
-				" If server crashes before truncate log is"
-				" removed make sure it is manually removed"
-				" before restarting server";
-			os_file_delete(innodb_log_file_key, m_log_file_name);
-			return;
-		}
-
-		byte	buffer[sizeof(TruncateLogger::s_magic)];
-		mach_write_to_4(buffer, TruncateLogger::s_magic);
-
-		dberr_t	err;
-
-		IORequest	request(IORequest::WRITE);
-
-		err = os_file_write(
-			request,
-			m_log_file_name, handle, buffer, 0, sizeof(buffer));
-
-		if (err != DB_SUCCESS) {
-
-			ib::error()
-				<< "IO: Failed to write the magic number to '"
-				<< m_log_file_name << "'";
-		}
-
-		DBUG_EXECUTE_IF("ib_trunc_crash_after_updating_magic_no",
-				DBUG_SUICIDE(););
-		os_file_flush(handle);
-		os_file_close(handle);
-		DBUG_EXECUTE_IF("ib_trunc_crash_after_logging_complete",
-				log_buffer_flush_to_disk();
-				os_thread_sleep(1000000);
-				DBUG_SUICIDE(););
-		os_file_delete(innodb_log_file_key, m_log_file_name);
-	}
-
-private:
-	// Disably copying
-	TruncateLogger(const TruncateLogger&);
-	TruncateLogger& operator=(const TruncateLogger&);
-
-private:
-	/** Lookup the index using the index id.
-	@return index instance if found else NULL */
-	const dict_index_t* find(index_id_t id) const
-	{
-		for (const dict_index_t* index = UT_LIST_GET_FIRST(
-				m_table->indexes);
-		     index != NULL;
-		     index = UT_LIST_GET_NEXT(indexes, index)) {
-
-			if (index->id == id) {
-				return(index);
-			}
-		}
-
-		return(NULL);
-	}
-
-private:
-	/** Table to be truncated */
-	dict_table_t*		m_table;
-
-	/** Tablespace flags */
-	ulint			m_flags;
-
-	/** Collect table to truncate information */
-	truncate_t		m_truncate;
-
-	/** Truncate log file name. */
-	char*			m_log_file_name;
-
-
-public:
-	/** Magic Number to indicate truncate action is complete. */
-	const static ib_uint32_t	s_magic;
-
-	/** Truncate Log file Prefix. */
-	const static char*		s_log_prefix;
-
-	/** Truncate Log file Extension. */
-	const static char*		s_log_ext;
-};
-
-const ib_uint32_t	TruncateLogger::s_magic = 32743712;
-const char*		TruncateLogger::s_log_prefix = "ib_";
-const char*		TruncateLogger::s_log_ext = "trunc.log";
-
 /**
 Scan to find out truncate log file from the given directory path.
 
@@ -583,9 +254,7 @@ TruncateLogParser::scan(
 	os_file_dir_t	dir;
 	os_file_stat_t	fileinfo;
 	dberr_t		err = DB_SUCCESS;
-	ulint		ext_len = strlen(TruncateLogger::s_log_ext);
-	ulint		prefix_len = strlen(TruncateLogger::s_log_prefix);
-	ulint		dir_len = strlen(dir_path);
+	const ulint	dir_len = strlen(dir_path);
 
 	/* Scan and look out for the truncate log files. */
 	dir = os_file_opendir(dir_path, true);
@@ -599,12 +268,11 @@ TruncateLogParser::scan(
 		ulint nm_len = strlen(fileinfo.name);
 
 		if (fileinfo.type == OS_FILE_TYPE_FILE
-		    && nm_len > ext_len + prefix_len
-		    && (0 == strncmp(fileinfo.name + nm_len - ext_len,
-				     TruncateLogger::s_log_ext, ext_len))
-		    && (0 == strncmp(fileinfo.name,
-				     TruncateLogger::s_log_prefix,
-				     prefix_len))) {
+		    && nm_len > sizeof "ib_trunc.log"
+		    && (0 == strncmp(fileinfo.name + nm_len
+				     - ((sizeof "trunc.log") - 1),
+				     "trunc.log", (sizeof "trunc.log") - 1))
+		    && (0 == strncmp(fileinfo.name, "ib_", 3))) {
 
 			if (fileinfo.size == 0) {
 				/* Truncate log not written. Remove the file. */
@@ -614,7 +282,7 @@ TruncateLogParser::scan(
 			}
 
 			/* Construct file name by appending directory path */
-			ulint	sz = dir_len + 22 + 22 + 1 + ext_len + prefix_len;
+			ulint	sz = dir_len + 22 + 22 + sizeof "ib_trunc.log";
 			char*	log_file_name = UT_NEW_ARRAY_NOKEY(char, sz);
 			if (log_file_name == NULL) {
 				err = DB_OUT_OF_MEMORY;
@@ -687,8 +355,7 @@ TruncateLogParser::parse(
 			break;
 		}
 
-		ulint	magic_n = mach_read_from_4(log_buf);
-		if (magic_n == TruncateLogger::s_magic) {
+		if (mach_read_from_4(log_buf) == 32743712) {
 
 			/* Truncate action completed. Avoid parsing the file. */
 			os_file_close(handle);
@@ -884,58 +551,6 @@ class TableLocator : public Callback {
 	bool			m_table_found;
 };
 
-/**
-@param mtr	mini-transaction covering the read
-@param pcur	persistent cursor used for reading
-@return DB_SUCCESS or error code */
-dberr_t
-TruncateLogger::operator()(mtr_t* mtr, btr_pcur_t* pcur)
-{
-	ulint			len;
-	const byte*		field;
-	rec_t*			rec = btr_pcur_get_rec(pcur);
-	truncate_t::index_t	index;
-
-	field = rec_get_nth_field_old(
-		rec, DICT_FLD__SYS_INDEXES__TYPE, &len);
-	ut_ad(len == 4);
-	index.m_type = mach_read_from_4(field);
-
-	field = rec_get_nth_field_old(rec, DICT_FLD__SYS_INDEXES__ID, &len);
-	ut_ad(len == 8);
-	index.m_id = mach_read_from_8(field);
-
-	field = rec_get_nth_field_old(
-			rec, DICT_FLD__SYS_INDEXES__PAGE_NO, &len);
-	ut_ad(len == 4);
-	index.m_root_page_no = mach_read_from_4(field);
-
-	/* For compressed tables we need to store extra meta-data
-	required during btr_create(). */
-	if (FSP_FLAGS_GET_ZIP_SSIZE(m_flags)) {
-
-		const dict_index_t* dict_index = find(index.m_id);
-
-		if (dict_index != NULL) {
-
-			dberr_t err = index.set(dict_index);
-
-			if (err != DB_SUCCESS) {
-				m_truncate.clear();
-				return(err);
-			}
-
-		} else {
-			ib::warn() << "Index id " << index.m_id
-				<< " not found";
-		}
-	}
-
-	m_truncate.add(index);
-
-	return(DB_SUCCESS);
-}
-
 /**
 Drop an index in the table.
 
@@ -1121,251 +736,6 @@ TableLocator::operator()(mtr_t* mtr, btr_pcur_t* pcur)
 	return(DB_SUCCESS);
 }
 
-/**
-Rollback the transaction and release the index locks.
-Drop indexes if table is corrupted so that drop/create
-sequence works as expected.
-
-@param table			table to truncate
-@param trx			transaction covering the TRUNCATE
-@param new_id			new table id that was suppose to get assigned
-				to the table if truncate executed successfully.
-@param has_internal_doc_id	indicate existence of fts index
-@param no_redo			if true, turn-off redo logging
-@param corrupted		table corrupted status
-@param unlock_index		if true then unlock indexes before action */
-static
-void
-row_truncate_rollback(
-	dict_table_t*	table,
-	trx_t*		trx,
-	table_id_t	new_id,
-	bool		has_internal_doc_id,
-	bool		no_redo,
-	bool		corrupted,
-	bool		unlock_index)
-{
-	if (unlock_index) {
-		dict_table_x_unlock_indexes(table);
-	}
-
-	trx->error_state = DB_SUCCESS;
-
-	trx_rollback_to_savepoint(trx, NULL);
-
-	trx->error_state = DB_SUCCESS;
-
-	if (corrupted && !dict_table_is_temporary(table)) {
-
-		/* Cleanup action to ensure we don't left over stale entries
-		if we are marking table as corrupted. This will ensure
-		it can be recovered using drop/create sequence. */
-		dict_table_x_lock_indexes(table);
-
-		DropIndex       dropIndex(table, no_redo);
-
-		SysIndexIterator().for_each(dropIndex);
-
-		dict_table_x_unlock_indexes(table);
-
-		for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
-		     index != NULL;
-		     index = UT_LIST_GET_NEXT(indexes, index)) {
-
-			dict_set_corrupted(index, trx, "TRUNCATE TABLE");
-		}
-
-		if (has_internal_doc_id) {
-
-			ut_ad(!trx_is_started(trx));
-
-			table_id_t      id = table->id;
-
-			table->id = new_id;
-
-			fts_drop_tables(trx, table);
-
-			table->id = id;
-
-			ut_ad(trx_is_started(trx));
-
-			trx_commit_for_mysql(trx);
-		}
-
-	} else if (corrupted && dict_table_is_temporary(table)) {
-
-		dict_table_x_lock_indexes(table);
-
-		for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
-		     index != NULL;
-		     index = UT_LIST_GET_NEXT(indexes, index)) {
-
-			dict_drop_index_tree_in_mem(index, index->page);
-
-			index->page = FIL_NULL;
-		}
-
-		dict_table_x_unlock_indexes(table);
-	}
-
-	table->corrupted = corrupted;
-}
-
-/**
-Finish the TRUNCATE operations for both commit and rollback.
-
-@param table		table being truncated
-@param trx		transaction covering the truncate
-@param fsp_flags	tablespace flags
-@param logger		table to truncate information logger
-@param err		status of truncate operation
-
-@return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((warn_unused_result))
-dberr_t
-row_truncate_complete(
-	dict_table_t*		table,
-	trx_t*			trx,
-	ulint			fsp_flags,
-	TruncateLogger*		&logger,
-	dberr_t			err)
-{
-	bool	is_file_per_table = dict_table_is_file_per_table(table);
-
-	/* Add the table back to FTS optimize background thread. */
-	if (table->fts) {
-		fts_optimize_add_table(table);
-	}
-
-	row_mysql_unlock_data_dictionary(trx);
-
-	DEBUG_SYNC_C("ib_trunc_table_trunc_completing");
-
-	if (!dict_table_is_temporary(table)) {
-
-		DBUG_EXECUTE_IF("ib_trunc_crash_before_log_removal",
-				log_buffer_flush_to_disk();
-				os_thread_sleep(500000);
-				DBUG_SUICIDE(););
-
-		/* Note: We don't log-checkpoint instead we have written
-		a special REDO log record MLOG_TRUNCATE that is used to
-		avoid applying REDO records before truncate for crash
-		that happens post successful truncate completion. */
-
-		if (logger != NULL) {
-			logger->done();
-			UT_DELETE(logger);
-			logger = NULL;
-		}
-	}
-
-	/* If non-temp file-per-table tablespace... */
-	if (is_file_per_table
-	    && !dict_table_is_temporary(table)
-	    && fsp_flags != ULINT_UNDEFINED) {
-
-		/* This function will reset back the stop_new_ops
-		and is_being_truncated so that fil-ops can re-start. */
-		dberr_t err2 = truncate_t::truncate(
-			table->space,
-			table->data_dir_path,
-			table->name.m_name, fsp_flags, false);
-
-		if (err2 != DB_SUCCESS) {
-			return(err2);
-		}
-	}
-
-	if (err == DB_SUCCESS) {
-		dict_stats_update(table, DICT_STATS_EMPTY_TABLE);
-	}
-
-	trx->op_info = "";
-
-	/* For temporary tables or if there was an error, we need to reset
-	the dict operation flags. */
-	trx->ddl = false;
-	trx->dict_operation = TRX_DICT_OP_NONE;
-
-	ut_ad(!trx_is_started(trx));
-
-	srv_wake_master_thread();
-
-	DBUG_EXECUTE_IF("ib_trunc_crash_after_truncate_done",
-			DBUG_SUICIDE(););
-
-	return(err);
-}
-
-/**
-Handle FTS truncate issues.
-@param table		table being truncated
-@param new_id		new id for the table
-@param trx		transaction covering the truncate
-@return DB_SUCCESS or error code. */
-static MY_ATTRIBUTE((warn_unused_result))
-dberr_t
-row_truncate_fts(
-	dict_table_t*	table,
-	table_id_t	new_id,
-	trx_t*		trx)
-{
-	dict_table_t	fts_table;
-
-	fts_table.id = new_id;
-	fts_table.name = table->name;
-	fts_table.flags2 = table->flags2;
-	fts_table.flags = table->flags;
-	fts_table.space = table->space;
-
-	/* table->data_dir_path is used for FTS AUX table
-	creation. */
-	if (DICT_TF_HAS_DATA_DIR(table->flags)
-	    && table->data_dir_path == NULL) {
-		dict_get_and_save_data_dir_path(table, true);
-		ut_ad(table->data_dir_path != NULL);
-	}
-
-	fts_table.data_dir_path = table->data_dir_path;
-
-	dberr_t		err;
-
-	err = fts_create_common_tables(
-		trx, &fts_table, table->name.m_name, TRUE);
-
-	for (ulint i = 0;
-	     i < ib_vector_size(table->fts->indexes) && err == DB_SUCCESS;
-	     i++) {
-
-		dict_index_t*	fts_index;
-
-		fts_index = static_cast<dict_index_t*>(
-			ib_vector_getp(table->fts->indexes, i));
-
-		err = fts_create_index_tables_low(
-			trx, fts_index, table->name.m_name, new_id);
-	}
-
-	DBUG_EXECUTE_IF("ib_err_trunc_during_fts_trunc",
-			err = DB_ERROR;);
-
-	if (err != DB_SUCCESS) {
-
-		trx->error_state = DB_SUCCESS;
-		trx_rollback_to_savepoint(trx, NULL);
-		trx->error_state = DB_SUCCESS;
-
-		ib::error() << "Unable to truncate FTS index for table "
-			<< table->name;
-	} else {
-
-		ut_ad(trx_is_started(trx));
-	}
-
-	return(err);
-}
-
 /**
 Update system table to reflect new table id.
 @param old_table_id		old table id
@@ -1506,629 +876,6 @@ row_truncate_update_sys_tables_during_fix_up(
 	return(err);
 }
 
-/**
-Truncate also results in assignment of new table id, update the system
-SYSTEM TABLES with the new id.
-@param table,			table being truncated
-@param new_id,			new table id
-@param has_internal_doc_id,	has doc col (fts)
-@param no_redo			if true, turn-off redo logging
-@param trx			transaction handle
-@return	error code or DB_SUCCESS */
-static MY_ATTRIBUTE((warn_unused_result))
-dberr_t
-row_truncate_update_system_tables(
-	dict_table_t*	table,
-	table_id_t	new_id,
-	bool		has_internal_doc_id,
-	bool		no_redo,
-	trx_t*		trx)
-{
-	dberr_t		err	= DB_SUCCESS;
-
-	ut_a(!dict_table_is_temporary(table));
-
-	err = row_truncate_update_table_id(table->id, new_id, FALSE, trx);
-
-	DBUG_EXECUTE_IF("ib_err_trunc_during_sys_table_update",
-			err = DB_ERROR;);
-
-	if (err != DB_SUCCESS) {
-
-		row_truncate_rollback(
-			table, trx, new_id, has_internal_doc_id,
-			no_redo, true, false);
-
-		ib::error() << "Unable to assign a new identifier to table "
-			<< table->name << " after truncating it. Marked the"
-			" table as corrupted. In-memory representation is now"
-			" different from the on-disk representation.";
-		err = DB_ERROR;
-	} else {
-		/* Drop the old FTS index */
-		if (has_internal_doc_id) {
-
-			ut_ad(trx_is_started(trx));
-
-			fts_drop_tables(trx, table);
-
-			DBUG_EXECUTE_IF("ib_truncate_crash_while_fts_cleanup",
-					DBUG_SUICIDE(););
-
-			ut_ad(trx_is_started(trx));
-		}
-
-		DBUG_EXECUTE_IF("ib_trunc_crash_after_fts_drop",
-				log_buffer_flush_to_disk();
-				os_thread_sleep(2000000);
-				DBUG_SUICIDE(););
-
-		dict_table_change_id_in_cache(table, new_id);
-
-		/* Reset the Doc ID in cache to 0 */
-		if (has_internal_doc_id && table->fts->cache != NULL) {
-			DBUG_EXECUTE_IF("ib_trunc_sleep_before_fts_cache_clear",
-					os_thread_sleep(10000000););
-
-			table->fts->fts_status |= TABLE_DICT_LOCKED;
-			fts_update_next_doc_id(trx, table, NULL, 0);
-			fts_cache_clear(table->fts->cache);
-			fts_cache_init(table->fts->cache);
-			table->fts->fts_status &= uint(~TABLE_DICT_LOCKED);
-		}
-	}
-
-	return(err);
-}
-
-/**
-Prepare for the truncate process. On success all of the table's indexes will
-be locked in X mode.
-@param table		table to truncate
-@param flags		tablespace flags
-@return	error code or DB_SUCCESS */
-static MY_ATTRIBUTE((warn_unused_result))
-dberr_t
-row_truncate_prepare(dict_table_t* table, ulint* flags)
-{
-	ut_ad(!dict_table_is_temporary(table));
-	ut_ad(dict_table_is_file_per_table(table));
-
-	*flags = fil_space_get_flags(table->space);
-
-	ut_ad(!dict_table_is_temporary(table));
-
-	dict_get_and_save_data_dir_path(table, true);
-
-	if (*flags != ULINT_UNDEFINED) {
-
-		dberr_t	err = fil_prepare_for_truncate(table->space);
-
-		if (err != DB_SUCCESS) {
-			return(err);
-		}
-	}
-
-	return(DB_SUCCESS);
-}
-
-/**
-Do foreign key checks before starting TRUNCATE.
-@param table		table being truncated
-@param trx		transaction covering the truncate
-@return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((warn_unused_result))
-dberr_t
-row_truncate_foreign_key_checks(
-	const dict_table_t*	table,
-	const trx_t*		trx)
-{
-	/* Check if the table is referenced by foreign key constraints from
-	some other table (not the table itself) */
-
-	dict_foreign_set::iterator	it
-		= std::find_if(table->referenced_set.begin(),
-			       table->referenced_set.end(),
-			       dict_foreign_different_tables());
-
-	if (!srv_read_only_mode
-	    && it != table->referenced_set.end()
-	    && trx->check_foreigns) {
-
-		dict_foreign_t*	foreign = *it;
-
-		FILE*	ef = dict_foreign_err_file;
-
-		/* We only allow truncating a referenced table if
-		FOREIGN_KEY_CHECKS is set to 0 */
-
-		mutex_enter(&dict_foreign_err_mutex);
-
-		rewind(ef);
-
-		ut_print_timestamp(ef);
-
-		fputs("  Cannot truncate table ", ef);
-		ut_print_name(ef, trx, table->name.m_name);
-		fputs(" by DROP+CREATE\n"
-		      "InnoDB: because it is referenced by ", ef);
-		ut_print_name(ef, trx, foreign->foreign_table_name);
-		putc('\n', ef);
-
-		mutex_exit(&dict_foreign_err_mutex);
-
-		return(DB_ERROR);
-	}
-
-	/* TODO: could we replace the counter n_foreign_key_checks_running
-	with lock checks on the table? Acquire here an exclusive lock on the
-	table, and rewrite lock0lock.cc and the lock wait in srv0srv.cc so that
-	they can cope with the table having been truncated here? Foreign key
-	checks take an IS or IX lock on the table. */
-
-	if (table->n_foreign_key_checks_running > 0) {
-		ib::warn() << "Cannot truncate table " << table->name
-			<< " because there is a foreign key check running on"
-			" it.";
-
-		return(DB_ERROR);
-	}
-
-	return(DB_SUCCESS);
-}
-
-/**
-Do some sanity checks before starting the actual TRUNCATE.
-@param table		table being truncated
-@return DB_SUCCESS or error code */
-static MY_ATTRIBUTE((warn_unused_result))
-dberr_t
-row_truncate_sanity_checks(
-	const dict_table_t* table)
-{
-	if (dict_table_is_discarded(table)) {
-
-		return(DB_TABLESPACE_DELETED);
-
-	} else if (!table->is_readable()) {
-		if (fil_space_get(table->space) == NULL) {
-			return(DB_TABLESPACE_NOT_FOUND);
-
-		} else {
-			return(DB_DECRYPTION_FAILED);
-		}
-	} else if (dict_table_is_corrupted(table)) {
-
-		return(DB_TABLE_CORRUPT);
-	}
-
-	return(DB_SUCCESS);
-}
-
-/**
-Truncates a table for MySQL.
-@param table		table being truncated
-@param trx		transaction covering the truncate
-@return	error code or DB_SUCCESS */
-dberr_t
-row_truncate_table_for_mysql(
-	dict_table_t* table,
-	trx_t* trx)
-{
-	bool	is_file_per_table = dict_table_is_file_per_table(table);
-	dberr_t		err;
-#ifdef UNIV_DEBUG
-	ulint		old_space = table->space;
-#endif /* UNIV_DEBUG */
-	TruncateLogger*	logger = NULL;
-
-	/* Understanding the truncate flow.
-
-	Step-1: Perform intiial sanity check to ensure table can be truncated.
-	This would include check for tablespace discard status, ibd file
-	missing, etc ....
-
-	Step-2: Start transaction (only for non-temp table as temp-table don't
-	modify any data on disk doesn't need transaction object).
-
-	Step-3: Validate ownership of needed locks (Exclusive lock).
-	Ownership will also ensure there is no active SQL queries, INSERT,
-	SELECT, .....
-
-	Step-4: Stop all the background process associated with table.
-
-	Step-5: There are few foreign key related constraint under which
-	we can't truncate table (due to referential integrity unless it is
-	turned off). Ensure this condition is satisfied.
-
-	Step-6: Truncate operation can be rolled back in case of error
-	till some point. Associate rollback segment to record undo log.
-
-	Step-7: Generate new table-id.
-	Why we need new table-id ?
-	Purge and rollback case: we assign a new table id for the table.
-	Since purge and rollback look for the table based on the table id,
-	they see the table as 'dropped' and discard their operations.
-
-	Step-8: Log information about tablespace which includes
-	table and index information. If there is a crash in the next step
-	then during recovery we will attempt to fixup the operation.
-
-	Step-9: Drop all indexes (this include freeing of the pages
-	associated with them).
-
-	Step-10: Re-create new indexes.
-
-	Step-11: Update new table-id to in-memory cache (dictionary),
-	on-disk (INNODB_SYS_TABLES). INNODB_SYS_INDEXES also needs to
-	be updated to reflect updated root-page-no of new index created
-	and updated table-id.
-
-	Step-12: Cleanup Stage. Reset auto-inc value to 1.
-	Release all the locks.
-	Commit the transaction. Update trx operation state.
-
-	Notes:
-	- On error, log checkpoint is done followed writing of magic number to
-	truncate log file. If servers crashes after truncate, fix-up action
-	will not be applied.
-
-	- log checkpoint is done before starting truncate table to ensure
-	that previous REDO log entries are not applied if current truncate
-	crashes. Consider following use-case:
-	 - create table .... insert/load table .... truncate table (crash)
-	 - on restart table is restored .... truncate table (crash)
-	 - on restart (assuming default log checkpoint is not done) will have
-	   2 REDO log entries for same table. (Note 2 REDO log entries
-	   for different table is not an issue).
-	For system-tablespace we can't truncate the tablespace so we need
-	to initiate a local cleanup that involves dropping of indexes and
-	re-creating them. If we apply stale entry we might end-up issuing
-	drop on wrong indexes.
-
-	- Insert buffer: TRUNCATE TABLE is analogous to DROP TABLE,
-	so we do not have to remove insert buffer records, as the
-	insert buffer works at a low level. If a freed page is later
-	reallocated, the allocator will remove the ibuf entries for
-	it. When we prepare to truncate *.ibd files, we remove all entries
-	for the table in the insert buffer tree. This is not strictly
-	necessary, but we can free up some space in the system tablespace.
-
-	- Linear readahead and random readahead: we use the same
-	method as in 3) to discard ongoing operations. (This is only
-	relevant for TRUNCATE TABLE by TRUNCATE TABLESPACE.)
-	Ensure that the table will be dropped by trx_rollback_active() in
-	case of a crash.
-	*/
-
-	/*-----------------------------------------------------------------*/
-	/* Step-1: Perform intiial sanity check to ensure table can be
-	truncated. This would include check for tablespace discard status,
-	ibd file missing, etc .... */
-	err = row_truncate_sanity_checks(table);
-	if (err != DB_SUCCESS) {
-		return(err);
-
-	}
-
-	/* Step-2: Start transaction (only for non-temp table as temp-table
-	don't modify any data on disk doesn't need transaction object). */
-	if (!dict_table_is_temporary(table)) {
-		if (table->fts) {
-			fts_optimize_remove_table(table);
-		}
-
-		/* Avoid transaction overhead for temporary table DDL. */
-		trx_start_for_ddl(trx, TRX_DICT_OP_TABLE);
-	}
-
-	DEBUG_SYNC_C("row_trunc_before_dict_lock");
-
-	/* Step-3: Validate ownership of needed locks (Exclusive lock).
-	Ownership will also ensure there is no active SQL queries, INSERT,
-	SELECT, .....*/
-	trx->op_info = "truncating table";
-	ut_a(trx->dict_operation_lock_mode == 0);
-	row_mysql_lock_data_dictionary(trx);
-	ut_ad(mutex_own(&dict_sys->mutex));
-	ut_ad(rw_lock_own(dict_operation_lock, RW_LOCK_X));
-
-	/* Step-4: Stop all the background process associated with table. */
-	dict_stats_wait_bg_to_stop_using_table(table, trx);
-
-	/* Step-5: There are few foreign key related constraint under which
-	we can't truncate table (due to referential integrity unless it is
-	turned off). Ensure this condition is satisfied. */
-	ulint	fsp_flags = ULINT_UNDEFINED;
-	err = row_truncate_foreign_key_checks(table, trx);
-	if (err != DB_SUCCESS) {
-		trx_rollback_to_savepoint(trx, NULL);
-		return(row_truncate_complete(
-				table, trx, fsp_flags, logger, err));
-	}
-
-	/* Remove all locks except the table-level X lock. */
-	lock_remove_all_on_table(table, FALSE);
-	trx->table_id = table->id;
-	trx_set_dict_operation(trx, TRX_DICT_OP_TABLE);
-
-	/* Step-6: Truncate operation can be rolled back in case of error
-	till some point. Associate rollback segment to record undo log. */
-	if (!dict_table_is_temporary(table)) {
-		mutex_enter(&trx->undo_mutex);
-
-		trx_undo_t**	pundo = &trx->rsegs.m_redo.update_undo;
-		err = trx_undo_assign_undo(
-			trx, trx->rsegs.m_redo.rseg, pundo, TRX_UNDO_UPDATE);
-
-		mutex_exit(&trx->undo_mutex);
-
-		DBUG_EXECUTE_IF("ib_err_trunc_assigning_undo_log",
-				err = DB_ERROR;);
-		if (err != DB_SUCCESS) {
-			trx_rollback_to_savepoint(trx, NULL);
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, err));
-		}
-	}
-
-	/* Step-7: Generate new table-id.
-	Why we need new table-id ?
-	Purge and rollback: we assign a new table id for the
-	table. Since purge and rollback look for the table based on
-	the table id, they see the table as 'dropped' and discard
-	their operations. */
-	table_id_t	new_id;
-	dict_hdr_get_new_id(&new_id, NULL, NULL, table, false);
-
-	/* Check if table involves FTS index. */
-	bool	has_internal_doc_id =
-		dict_table_has_fts_index(table)
-		|| DICT_TF2_FLAG_IS_SET(table, DICT_TF2_FTS_HAS_DOC_ID);
-
-	bool	no_redo = is_file_per_table && !has_internal_doc_id;
-
-	/* Step-8: Log information about tablespace which includes
-	table and index information. If there is a crash in the next step
-	then during recovery we will attempt to fixup the operation. */
-
-	/* Lock all index trees for this table, as we will truncate
-	the table/index and possibly change their metadata. All
-	DML/DDL are blocked by table level X lock, with a few exceptions
-	such as queries into information schema about the table,
-	MySQL could try to access index stats for this kind of query,
-	we need to use index locks to sync up */
-	dict_table_x_lock_indexes(table);
-
-	if (!dict_table_is_temporary(table)) {
-
-		if (is_file_per_table) {
-
-			err = row_truncate_prepare(table, &fsp_flags);
-
-			DBUG_EXECUTE_IF("ib_err_trunc_preparing_for_truncate",
-					err = DB_ERROR;);
-
-			if (err != DB_SUCCESS) {
-				row_truncate_rollback(
-					table, trx, new_id,
-					has_internal_doc_id,
-					no_redo, false, true);
-				return(row_truncate_complete(
-					table, trx, fsp_flags, logger, err));
-			}
-		} else {
-			fsp_flags = fil_space_get_flags(table->space);
-
-			DBUG_EXECUTE_IF("ib_err_trunc_preparing_for_truncate",
-					fsp_flags = ULINT_UNDEFINED;);
-
-			if (fsp_flags == ULINT_UNDEFINED) {
-				row_truncate_rollback(
-					table, trx, new_id,
-					has_internal_doc_id,
-					no_redo, false, true);
-				return(row_truncate_complete(
-						table, trx, fsp_flags,
-						logger, DB_ERROR));
-			}
-		}
-
-		logger = UT_NEW_NOKEY(TruncateLogger(
-				table, fsp_flags, new_id));
-
-		err = logger->init();
-		if (err != DB_SUCCESS) {
-			row_truncate_rollback(
-				table, trx, new_id, has_internal_doc_id,
-				no_redo, false, true);
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, DB_ERROR));
-
-		}
-
-		err = SysIndexIterator().for_each(*logger);
-		if (err != DB_SUCCESS) {
-			row_truncate_rollback(
-				table, trx, new_id, has_internal_doc_id,
-				no_redo, false, true);
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, DB_ERROR));
-
-		}
-
-		ut_ad(logger->debug());
-
-		err = logger->log();
-
-		if (err != DB_SUCCESS) {
-			row_truncate_rollback(
-				table, trx, new_id, has_internal_doc_id,
-				no_redo, false, true);
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, DB_ERROR));
-		}
-	}
-
-	DBUG_EXECUTE_IF("ib_trunc_crash_after_redo_log_write_complete",
-			log_buffer_flush_to_disk();
-			os_thread_sleep(3000000);
-			DBUG_SUICIDE(););
-
-	/* Step-9: Drop all indexes (free index pages associated with these
-	indexes) */
-	if (!dict_table_is_temporary(table)) {
-
-		DropIndex	dropIndex(table, no_redo);
-
-		err = SysIndexIterator().for_each(dropIndex);
-
-		if (err != DB_SUCCESS) {
-
-			row_truncate_rollback(
-				table, trx, new_id, has_internal_doc_id,
-				no_redo, true, true);
-
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, err));
-		}
-	} else {
-		/* For temporary tables we don't have entries in SYSTEM TABLES*/
-		ut_ad(fsp_is_system_temporary(table->space));
-		for (dict_index_t* index = UT_LIST_GET_FIRST(table->indexes);
-		     index != NULL;
-		     index = UT_LIST_GET_NEXT(indexes, index)) {
-
-			err = dict_truncate_index_tree_in_mem(index);
-
-			if (err != DB_SUCCESS) {
-				row_truncate_rollback(
-					table, trx, new_id, has_internal_doc_id,
-					no_redo, true, true);
-				return(row_truncate_complete(
-					table, trx, fsp_flags, logger, err));
-			}
-
-			DBUG_EXECUTE_IF(
-				"ib_trunc_crash_during_drop_index_temp_table",
-				log_buffer_flush_to_disk();
-				os_thread_sleep(2000000);
-				DBUG_SUICIDE(););
-		}
-	}
-
-	if (is_file_per_table && fsp_flags != ULINT_UNDEFINED) {
-		/* A single-table tablespace has initially
-		FIL_IBD_FILE_INITIAL_SIZE number of pages allocated and an
-		extra page is allocated for each of the indexes present. But in
-		the case of clust index 2 pages are allocated and as one is
-		covered in the calculation as part of table->indexes.count we
-		take care of the other page by adding 1. */
-		ulint	space_size = table->indexes.count +
-				FIL_IBD_FILE_INITIAL_SIZE + 1;
-
-		if (has_internal_doc_id) {
-			/* Since aux tables are created for fts indexes and
-			they use seperate tablespaces. */
-			space_size -= ib_vector_size(table->fts->indexes);
-		}
-
-		fil_reinit_space_header_for_table(table, space_size, trx);
-	}
-
-	DBUG_EXECUTE_IF("ib_trunc_crash_with_intermediate_log_checkpoint",
-			log_buffer_flush_to_disk();
-			os_thread_sleep(2000000);
-			log_checkpoint(TRUE, TRUE);
-			os_thread_sleep(1000000);
-			DBUG_SUICIDE(););
-
-	DBUG_EXECUTE_IF("ib_trunc_crash_drop_reinit_done_create_to_start",
-			log_buffer_flush_to_disk();
-			os_thread_sleep(2000000);
-			DBUG_SUICIDE(););
-
-	/* Step-10: Re-create new indexes. */
-	if (!dict_table_is_temporary(table)) {
-
-		CreateIndex	createIndex(table, no_redo);
-
-		err = SysIndexIterator().for_each(createIndex);
-
-		if (err != DB_SUCCESS) {
-
-			row_truncate_rollback(
-				table, trx, new_id, has_internal_doc_id,
-				no_redo, true, true);
-
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, err));
-		}
-	}
-
-	/* Done with index truncation, release index tree locks,
-	subsequent work relates to table level metadata change */
-	dict_table_x_unlock_indexes(table);
-
-	if (has_internal_doc_id) {
-
-		err = row_truncate_fts(table, new_id, trx);
-
-		if (err != DB_SUCCESS) {
-
-			row_truncate_rollback(
-				table, trx, new_id, has_internal_doc_id,
-				no_redo, true, false);
-
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, err));
-		}
-	}
-
-	/* Step-11: Update new table-id to in-memory cache (dictionary),
-	on-disk (INNODB_SYS_TABLES). INNODB_SYS_INDEXES also needs to
-	be updated to reflect updated root-page-no of new index created
-	and updated table-id. */
-	if (dict_table_is_temporary(table)) {
-
-		dict_table_change_id_in_cache(table, new_id);
-		err = DB_SUCCESS;
-
-	} else {
-
-		/* If this fails then we are in an inconsistent state and
-		the results are undefined. */
-		ut_ad(old_space == table->space);
-
-		err = row_truncate_update_system_tables(
-			table, new_id, has_internal_doc_id, no_redo, trx);
-
-		if (err != DB_SUCCESS) {
-			return(row_truncate_complete(
-				table, trx, fsp_flags, logger, err));
-		}
-	}
-
-	DBUG_EXECUTE_IF("ib_trunc_crash_on_updating_dict_sys_info",
-			log_buffer_flush_to_disk();
-			os_thread_sleep(2000000);
-			DBUG_SUICIDE(););
-
-	/* Step-12: Cleanup Stage. Reset auto-inc value to 1.
-	Release all the locks.
-	Commit the transaction. Update trx operation state. */
-	dict_table_autoinc_lock(table);
-	dict_table_autoinc_initialize(table, 1);
-	dict_table_autoinc_unlock(table);
-
-	if (trx_is_started(trx)) {
-
-		trx_commit_for_mysql(trx);
-	}
-
-	return(row_truncate_complete(table, trx, fsp_flags, logger, err));
-}
-
 /**
 Fix the table truncate by applying information parsed from TRUNCATE log.
 Fix-up includes re-creating table (drop and re-create indexes)
diff --git a/storage/innobase/row/row0upd.cc b/storage/innobase/row/row0upd.cc
index 171e06894ca..342f0d222e0 100644
--- a/storage/innobase/row/row0upd.cc
+++ b/storage/innobase/row/row0upd.cc
@@ -286,34 +286,6 @@ row_upd_check_references_constraints(
 					FALSE, FALSE, DICT_ERR_IGNORE_NONE);
 			}
 
-			/* dict_operation_lock is held both here
-			(UPDATE or DELETE with FOREIGN KEY) and by TRUNCATE
-			TABLE operations.
-			If a TRUNCATE TABLE operation is in progress,
-			there can be 2 possible conditions:
-			1) row_truncate_table_for_mysql() is not yet called.
-			2) Truncate releases dict_operation_lock
-			during eviction of pages from buffer pool
-			for a file-per-table tablespace.
-
-			In case of (1), truncate will wait for FK operation
-			to complete.
-			In case of (2), truncate will be rolled forward even
-			if it is interrupted. So if the foreign table is
-			undergoing a truncate, ignore the FK check. */
-
-			if (foreign_table) {
-				mutex_enter(&fil_system->mutex);
-				const fil_space_t* space = fil_space_get_by_id(
-					foreign_table->space);
-				const bool being_truncated = space
-					&& space->is_being_truncated;
-				mutex_exit(&fil_system->mutex);
-				if (being_truncated) {
-					continue;
-				}
-			}
-
 			/* NOTE that if the thread ends up waiting for a lock
 			we will release dict_operation_lock temporarily!
 			But the counter on the table protects 'foreign' from
diff --git a/storage/innobase/trx/trx0undo.cc b/storage/innobase/trx/trx0undo.cc
index c93003f9e03..1e85ce2086a 100644
--- a/storage/innobase/trx/trx0undo.cc
+++ b/storage/innobase/trx/trx0undo.cc
@@ -1896,33 +1896,27 @@ trx_undo_free_prepared(
 bool
 trx_undo_truncate_tablespace(
 	undo::Truncate*	undo_trunc)
-
 {
-	bool	success = true;
 	ulint	space_id = undo_trunc->get_marked_space_id();
+	ut_a(srv_is_undo_tablespace(space_id));
 
-	/* Step-1: Truncate tablespace. */
-	success = fil_truncate_tablespace(
-		space_id, SRV_UNDO_TABLESPACE_SIZE_IN_PAGES);
+	/* Adjust the tablespace metadata. */
+	fil_space_t* space = fil_truncate_prepare(space_id);
 
-	if (!success) {
-		return(success);
+	if (!space) {
+		return false;
 	}
 
-	/* Step-2: Re-initialize tablespace header.
-	Avoid REDO logging as we don't want to apply the action if server
-	crashes. For fix-up we have UNDO-truncate-ddl-log. */
-	mtr_t		mtr;
-	mtr_start(&mtr);
-	mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
-	fsp_header_init(space_id, SRV_UNDO_TABLESPACE_SIZE_IN_PAGES, &mtr);
-	mtr_commit(&mtr);
+	/* Undo tablespace always are a single file. */
+	ut_a(UT_LIST_GET_LEN(space->chain) == 1);
 
-	/* Step-3: Re-initialize rollback segment header that resides
-	in truncated tablespaced. */
-	mtr_start(&mtr);
-	mtr_set_log_mode(&mtr, MTR_LOG_NO_REDO);
-	mtr_x_lock(fil_space_get_latch(space_id, NULL), &mtr);
+	/* Re-initialize tablespace, in a single mini-transaction. */
+	mtr_t mtr;
+	const ulint size = SRV_UNDO_TABLESPACE_SIZE_IN_PAGES;
+	mtr.start();
+	mtr_x_lock(&space->latch, &mtr);
+	fil_truncate_log(space, size, &mtr);
+	fsp_header_init(space_id, size, &mtr);
 
 	for (ulint i = 0; i < undo_trunc->rsegs_size(); ++i) {
 		trx_rsegf_t*	rseg_header;
@@ -1968,23 +1962,46 @@ trx_undo_truncate_tablespace(
 		UT_LIST_INIT(rseg->insert_undo_list, &trx_undo_t::undo_list);
 		UT_LIST_INIT(rseg->insert_undo_cached, &trx_undo_t::undo_list);
 
-		rseg->max_size = mtr_read_ulint(
-			rseg_header + TRX_RSEG_MAX_SIZE, MLOG_4BYTES, &mtr);
+		/* These were written by trx_rseg_header_create(). */
+		ut_ad(mach_read_from_4(rseg_header + TRX_RSEG_MAX_SIZE)
+		      == FIL_NULL);
+		ut_ad(!mach_read_from_4(rseg_header + TRX_RSEG_HISTORY_SIZE));
 
-		/* Initialize the undo log lists according to the rseg header */
-		rseg->curr_size = mtr_read_ulint(
-			rseg_header + TRX_RSEG_HISTORY_SIZE, MLOG_4BYTES, &mtr)
-			+ 1;
-
-		ut_ad(rseg->curr_size == 1);
+		rseg->max_size = ULINT_MAX;
 
+		/* Initialize the undo log lists according to the rseg header */
+		rseg->curr_size = 1;
 		rseg->trx_ref_count = 0;
 		rseg->last_page_no = FIL_NULL;
 		rseg->last_offset = 0;
 		rseg->last_trx_no = 0;
 		rseg->last_del_marks = FALSE;
 	}
-	mtr_commit(&mtr);
 
-	return(success);
+	fil_node_t* file = UT_LIST_GET_FIRST(space->chain);
+
+	/* The undo tablespace files are never closed. */
+	ut_ad(file->is_open());
+
+	mutex_enter(&fil_system->mutex);
+	space->size = file->size = size;
+	mutex_exit(&fil_system->mutex);
+
+	mtr.commit();
+
+	if (os_file_truncate(file->name, file->handle, 0)) {
+		os_file_set_size(file->name, file->handle,
+				 os_offset_t(size) << srv_page_size_shift, 0);
+	}
+
+	/* TODO: PUNCH_HOLE the garbage (with write-ahead logging) */
+
+	mutex_enter(&fil_system->mutex);
+	ut_ad(space->stop_new_ops);
+	ut_ad(space->is_being_truncated);
+	space->stop_new_ops = false;
+	space->is_being_truncated = false;
+	mutex_exit(&fil_system->mutex);
+
+	return true;
 }
