WL#6501: InnoDB: Make Internal InnoDB TRUNCATE TABLE statement to be atomic for single tablespace

Status: Complete

RATIONALE
=========
* To make Internal InnoDB TRUNCATE TABLE statement to be atomic, reinitialize
  the original tablespace header with the same space id and then physically
  truncate its .ibd file during the truncation for single tablespace.


SUMMARY
=======
1. Introduce a new redo log entry type named MLOG_FILE_TRUNCATE.

2. Recreate the tablespace and table indexes by applying MLOG_FILE_TRUNCATE
   redo log entry during recovery when failing to create complete indexes
   during normal truncation, instead of dropping the table directly by
   flagging DICT_OP_TABLE for single tablespace.

3. Reinitialize the original tablespace header with the same space id and
   then physically truncate its .ibd file during the normal truncation for
   single tablespace, instead of dropping original tablespace and creating
   a new one with different space id.


LIMITATIONS
===========
1. Don't support to create FTS index when recreating the tablespace
   and table indexes by applying MLOG_FILE_TRUNCATE redo log entry
   during recovery as the data dictionary can't be accessed in that phase.

2. Don't resolve issues around FOREIGN KEY constraint on the truncating
   table, which is another separate problem.

3. Truncate is not atomic for partitioned table as partition create more than
one ibd file. 

4. Truncate is not atomic for master-slave architecture as MySQL bin-logging
still doesn't support atomic DDL. This means on crash of master during truncate
operation, table on master can be out-of-sync from slave table copy. User needs
to note this and fixup the things accordingly if master crashes on truncate.


CONTEXT
=======
Internal InnoDB TRUNCATE TABLE statement is not atomic. Since it firstly
delete the original tablespace and then create a new tablespace with
different space id. So the space id mismatch or missing tablespace
problem is caused if a crash happened after the .ibd file is deleted,
and before the new .ibd file is created.


USECASES
========

There is a main point to the solution, a checkpoint will be written down
upon the truncation finish successfully. So
    1. To failed truncate, The TRUNCATE redo log record will be applied
       during recovery.
    2. To successful truncate, the TRUNCATE redo log record will not be
       applied during recovery.

To the following case:
create table t1(a int not null, b int not null, c int not null,
                primary key (a), index (b), index (c)) engine=innodb;

# INSERT1
let $n=10000;
while ($n)
{
  eval insert into t1 values($n,$n,$n);
  dec $n;
}

# TRUNCATION
truncate table t1;

# INSERT2
let $n=5000;
while ($n)
{
  eval insert into t1 values($n,$n,$n);
  dec $n;
}

The above TRUNCATE and INSERTs will generate the following operations
on the redo log:
1. write log records for INSERT1 (The ibd data file is extended)
2. write MLOG_FILE_TRUNCATE for TRUNCATE
3. write log records for freeing indexes
4. write log records for creating indexes
5. log checkpoint
6. write log records for INSERT2 (The ibd data file is extended)

If the server crashed after step 2, and before step 5, a new tablespace
and indexes will be created when applying the TRUNCATE redo log record,
and every hashed log record which belongs to the tablespace will not
be applied to pages of the tablespace. The real size of the tablespace
can be got from node size of the ibd file for judging whether the hashed
log record is outside bounds of the tablespace or not.

If the server crashed during step 6, The recovery will start from the last
checkpoint written down by the successful truncation. So the TRUNCATE redo
log record will be not applied. Every hashed log record from step 6 will
be applied into pages of the tablespace normally. The ibd data file is
extended by INSERT2. So the real size of the tablespace can be got from
node size of the ibd file during recovery, and no one page offset is
outside the real size of the tablespace.


EXAMPLES
========
The innodb internal TRUNCATE TABLE statement can always truncate
a table successfully when recovery from a crash during truncation
after the feature.
set global innodb_file_per_table=on;
TRUNCATE TABLE t1;