工具介绍

工具的名字叫做:  undrop-for-innodb

代码地址: https://github.com/twindb/undrop-for-innodb

官方文档: https://recovery.twindb.com/

介绍工具的一篇ppt  http://www.slideshare.net/akuzminsky/undrop-for-innodb

 

MySQL 执行 Drop Table或者 Drop Database 的时候,InnoDB并没有删除数据,数据的Page还在磁盘上。

如果innodb_file_per_table 被设置成了 OFF, 则数据库在ibdata1上,如果 innodb_file_per_table 被设置成了 ON, 则数据在 .ibd文件中,MySQL已经删除了这个文件。

 

安装恢复软件

  1. 首先安装软件所需要的包:  make  gcc flex  bison git

[root@centos~]# yum install make  gcc  flex bison git

 

  1. 下载代码

[root@centos~]# git clone https://github.com/twindb/undrop-for-innodb.git

Initializedempty Git repository in /root/undrop-for-innodb/.git/

remote:Counting objects: 221, done.

Receivingobjects: 100% (221/221), 1.10 MiB | 53 KiB/s, done.

remote: Total221 (delta 0), reused 0 (delta 0), pack-reused 221

Resolvingdeltas: 100% (53/53), done.

[root@centos~]# ls

anaconda-ks.cfg    MySQL-5.6.27-1.el6.x86_64.rpm-bundle.tar MySQL-embedded-5.6.27-1.el6.x86_64.rpm MySQL-shared-compat-5.6.27-1.el6.x86_64.rpm

install.log        MySQL-client-5.6.27-1.el6.x86_64.rpm     MySQL-server-5.6.27-1.el6.x86_64.rpm   MySQL-test-5.6.27-1.el6.x86_64.rpm

install.log.syslog  MySQL-devel-5.6.27-1.el6.x86_64.rpm      MySQL-shared-5.6.27-1.el6.x86_64.rpm   undrop-for-innodb

 

3.编译代码

[root@centos~]# cd undrop-for-innodb/

[root@centosundrop-for-innodb]# ls

check_data.c  dictionary    include         LICENSE   print_data.c recover_dictionary.sh sql_parser.l  stream_parser.c  tables_dict.c

c_parser.c    fetch_data.sh  innochecksum.c  Makefile README.md     sakila                 sql_parser.y  sys_parser.c     test.sh

[root@centosundrop-for-innodb]# make

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c stream_parser.c

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include  -pthread -lm  stream_parser.o -o stream_parser

flex  sql_parser.l

bison  -o sql_parser.c sql_parser.y

sql_parser.y:conflicts: 6 shift/reduce

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c sql_parser.c

lex.yy.c:3084:警告:‘yyunput’定义后未使用

lex.yy.c:3125:警告:‘input’定义后未使用

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c c_parser.c

./include/ctype-latin1.c:359:警告:‘my_mb_wc_latin1’定义后未使用

./include/ctype-latin1.c:372:警告:‘my_wc_mb_latin1’定义后未使用

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c tables_dict.c

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c print_data.c

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe -I./include -c check_data.c

cc-D_FILE_OFFSET_BITS=64 -Wall -g -O3 -pipe  -I./include  sql_parser.oc_parser.o tables_dict.o print_data.o check_data.o -o c_parser -pthread -lm

cc -D_FILE_OFFSET_BITS=64-Wall -g -O3 -pipe   -I./include -oinnochecksum_changer innochecksum.c

 

 

 

 

 

测试恢复数据

测试环境

数据库的版本:MySQL-server-5.6.27

操作系统:Centos6.7 Windows 7

 

测试场景1Drop Database (innodb_file_per_table=On)

创建数据库和测试表

我们先来看下创建好的数据库,有多少个文件。

[root@centos mysql]#ls

auto.cnf  centos.err centos.pid  ibdata1  ib_logfile0 ib_logfile1  mysql  mysql.sock performance_schema RPM_UPGRADE_HISTORY RPM_UPGRADE_MARKER-LAST  test

 

确认下我们的数据库的 innodb_file_per_table参数

mysql> show variables like '%per_table%';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_file_per_table | ON   |
+-----------------------+-------+
1 row in set (0.00 sec)

说明:OFF代表mysql是共享表空间,也就是所有库的数据都存放在一个ibdate1文件中

ON代表,每个表的存储空间都是独立的。

 

接下来创建爱数据库 test1 并创建测试表 test1

mysql>create database test1;

Query OK, 1row affected (0.00 sec)

mysql> usetest1;

Databasechanged

mysql>create table test1(id int);

Query OK, 0rows affected (0.14 sec)

mysql>insert into test1 values('1');

Query OK, 1row affected (0.54 sec)

mysql>insert into test1 select * from test1;     -----反复运行多次,直到有足够的数据量

Query OK,131072 rows affected (2.28 sec)

Records:131072  Duplicates: 0  Warnings: 0

mysql>commit;

Query OK, 0rows affected (0.00 sec)

 

我们来看下数据文件多了哪些。

[root@centosmysql]# ls

auto.cnf  centos.err centos.pid  ibdata1  ib_logfile0 ib_logfile1  mysql  mysql.sock performance_schema RPM_UPGRADE_HISTORY RPM_UPGRADE_MARKER-LAST  test  test1

多了一个test1的目录。进入目录看下

[root@centosmysql]# cd test1

[root@centostest1]# ls

db.opt  test1.frm test1.ibd

可以看到 test1.frm test1.ibd 2个文件。

ibdMySQL数据文件、索引文件,无法直接读取。
frm
是表结构文件,可以直接打开。

如果innodb_file_per_table 无论是ON还是OFF,都会有这2个文件,区别只是innodb_file_per_tableON的时候,数据时放在 .idb中,如果为OFF则放在ibdata1中。

 

我们来看下数据文件的大小:

[root@centostest1]# du -sh *

4.0K    db.opt

12K     test1.frm

72M     test1.ibd

 

[root@centosmysql]# du -sh *

4.0K    auto.cnf

4.0K    centos.err

4.0K    centos.pid

76M     ibdata1

49M     ib_logfile0

48M     ib_logfile1

1.7M    mysql

0       mysql.sock

636K    performance_schema

4.0K    RPM_UPGRADE_HISTORY

4.0K    RPM_UPGRADE_MARKER-LAST

4.0K    test

8.0K    test2

发现 test1.ibdibdata1 都增长的很厉害,不知道为什么,这个之后再研究。

 

接下来删除数据库test1

drop databasetest1.

 

开始恢复数据

 

注意这里 -f 后面的参数是 裸盘 的地址,如果你不知道可以用 df -h 查看.

-t 是这个磁盘的大小。

 

[root@centos~]# df -h /var/lib/mysql

Filesystem            Size  Used Avail Use% Mounted on

/dev/mapper/vg_centos-lv_root

                       50G  4.1G  43G   9% /

 

[root@centosundrop-for-innodb]#./stream_parser -f /dev/mapper/vg_centos-lv_root -t 50g

Opening file:/dev/mapper/vg_centos-lv_root

Fileinformation:

 

ID of devicecontaining file:            5

inodenumber:                         6454

protection:                          60660 (block device)

number of hardlinks:                    1

user ID ofowner:                        0

group ID ofowner:                       6

device ID (ifspecial file):         64768

blocksize forfilesystem I/O:         4096

number ofblocks allocated:              0

time of lastaccess:            1449240755 Fri Dec  4 22:52:35 2015

time of lastmodification:      1449240755 FriDec  4 22:52:35 2015

time of laststatus change:     1449240755 FriDec  4 22:52:35 2015

total size, inbytes:                    0 (0.000exp(+0))

 

Size to process:               53687091200 (50.000 GiB)

Worker(0):1.03% done. 2015-12-05 00:04:40 ETA(in 00:14:38). Processing speed: 57.700MiB/sec

Worker(0):2.04% done. 2015-12-05 00:06:18 ETA(in 00:16:06). Processing speed: 51.902MiB/sec

Worker(0):3.06% done. 2015-12-05 00:01:27 ETA(in 00:11:08). Processing speed: 74.221MiB/sec

Worker(0):4.07% done. 2015-12-05 00:04:39 ETA(in 00:14:11). Processing speed: 57.672MiB/sec

Worker(0):98.51% done. 2015-12-04 23:54:19 ETA(in 00:00:05). Processing speed: 129.971MiB/sec

Worker(0):99.53% done. 2015-12-04 23:54:15 ETA(in 00:00:00). Processing speed: 520.000MiB/sec

All workersfinished in 263 sec

 

                           

这里说明一下:

0000000000000001.page  恢复出来的 SYS_TABLES

0000000000000003.page  恢复出来的 SYS_INDEXES

 

创建存放恢复出来的文件的目录

[root@centosundrop-for-innodb]#mkdir -p dictionary dumps/default

 

[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-vg_centos-lv_root/FIL_PAGE_INDEX/0000000000000001.page -t./dictionary/SYS_TABLES.sql  -o./dumps/SYS_TABLES.dmp  -l./dumps/SYS_TABLES.sql

恢复数据,因为我们是恢复删除掉的数据,所以一定要加参数D(注意是大写的D)

然后查看生成出来的文件:

./dictionary/SYS_TABLES.sql     是创建表 SYS_TABLES的脚本。

./dumps/SYS_TABLES.dmp      SYS_TABLES表里面的内容

./dumps/SYS_TABLES.sql        是恢复数据到SYS_TABLESSQL语句。

 

这里我们查看 ./dumps/SYS_TABLES.dmp,可以看到我们删除掉的数据

因为我们在test1数据库中只有1test1表。所以这里只能看到一个 test1

可以看到 table_id 20

 

接下来我们看下索引的信息

可以看到,索引的ID 22

 

这里有个重点的地方,我们首先要有表结构的SQL语句。(如果没有的话,可以参考我另外的一篇文章来恢复表的结构)

创建 test1/test1.sql 输入如下内容

Create table test1

(

Id int

)

 

开始恢复数据:

./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/0000000000000022.page-t test1/test1.sql -o dumps/test1.dmmp -l dumps/test1.sql

 

启动数据库,创建数据库test1

mysql> create database test1;

Query OK, 1 row affected (0.03 sec)

 

mysql> use test1;

Database changed

 

运行 test1/test1.sql 创建表 test1, 然后运行 dumps/test1.sql 恢复数据

mysql> source dumps/test1.sql

Query OK, 0 rows affected (0.00 sec)

 

Query OK, 45794 rows affected (0.90 sec)

Records: 45794 Deleted: 0  Skipped: 0  Warnings:

 

检查数据,可以看到数据已经正常恢复了。

 

 

测试场景2Drop Database (innodb_file_per_table=OFF)

创建数据库和测试表

 

首先确认下 innodb_file_per_table的参数.

mysql> showvariables like 'inno%per%tab%';

+-----------------------+-------+

|Variable_name         | Value |

+-----------------------+-------+

|innodb_file_per_table | ON    |

+-----------------------+-------+

1 row in set(0.00 sec)

 

创建测试用的数据库表和数据

mysql>create database test6;

Query OK, 1row affected (0.00 sec)

 

mysql> usetest6

Databasechanged

mysql>create table a(id int);

Query OK, 0rows affected (0.08 sec)

 

mysql>create table b(id2 int);

Query OK, 0rows affected (0.06 sec)

 

mysql>insert into a values(1);

Query OK, 1row affected (0.07 sec)

 

mysql>insert into b values(1);

Query OK, 1row affected (0.04 sec)

 

mysql>commit;

Query OK, 0rows affected (0.00 sec)

 

查看下数据表的目录,可以看到只有 frm文件

[root@centostest6]# pwd

/var/lib/mysql/test6

[root@centostest6]# ls

a.frm  b.frm db.opt

 

反复执行 Insert into aselect * from a; 直到有足够大的数据。

[root@centosmysql]# du -sh ibdata1

76M     ibdata1

Ibdata1增长到了76M

 

删除数据库 test6

mysql> dropdatabase test6;

Query OK, 2rows affected (0.26 sec)

 

开始恢复数据

因为数据在ibdata1文件中,所以我们分析ibdata1文件

[root@centosundrop-for-innodb]# ./stream_parser -f /var/lib/mysql/ibdata1

Opening file:/var/lib/mysql/ibdata1

Fileinformation:

 

ID of devicecontaining file:        64768

inodenumber:                      2621728

protection:                         100660 (regular file)

number of hardlinks:                    1

user ID ofowner:                      498

group ID ofowner:                     497

device ID (ifspecial file):             0

blocksize forfilesystem I/O:         4096

number ofblocks allocated:         155648

time of lastaccess:            1449385451 SunDec  6 15:04:11 2015

time of lastmodification:      1449385922 SunDec  6 15:12:02 2015

time of laststatus change:     1449385922 SunDec  6 15:12:02 2015

total size, inbytes:             79691776 (76.000 MiB)

 

Size toprocess:                  79691776(76.000 MiB)

All workersfinished in 0 sec

 

剩下的步骤和之前的一样,首先获取到 我们删除掉的test6的数据库里面的表,从结果里面可以看到是 a b ID 分别是 24 25

[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page  -t ./dictionary/SYS_TABLES.sql  -o ./dumps/SYS_TABLES.dmp  -l ./dumps/SYS_TABLES.sql

[root@centosundrop-for-innodb]# cat ./dumps/SYS_TABLES.dmp

-- Page id: 8,Format: REDUNDANT, Records list: Invalid, Expected records: (0 10)

000000000F6A    55000008010182  SYS_TABLES      "test6/a"       24     1       1       0      64      ""      0

000000000F64    52000008060182  SYS_TABLES      "test6/b"       25     1       1       0      64      ""      0

 

获取表中的索引信息

[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page  -t ./dictionary/SYS_INDEXES.sql

-- Page id:11, Format: REDUNDANT, Records list: Invalid, Expected records: (0 12)

000000000F6A    55000008010110  SYS_INDEXES     24     26      "GEN\_CLUST\_INDEX"     0      1       0       4294967295

000000000F64    52000008060110  SYS_INDEXES     25     27      "GEN\_CLUST\_INDEX"     0      1       0       4294967295

-- Page id:11, Found records: 2, Lost records: YES, Leaf page: YES

-- Page id:11, Format: REDUNDANT, Records list: Invalid, Expected records: (0 12)

000000000F6A    55000008010110  SYS_INDEXES     24     26      "GEN\_CLUST\_INDEX"     0      1       0       4294967295

000000000F64    52000008060110  SYS_INDEXES     25     27      "GEN\_CLUST\_INDEX"     0      1       0       4294967295

SETFOREIGN_KEY_CHECKS=0;

LOAD DATALOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_INDEXES' REPLACE INTOTABLE `SYS_INDEXES` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"'LINES STARTING BY 'SYS_INDEXES\t' (`TABLE_ID`, `ID`, `NAME`, `N_FIELDS`,`TYPE`, `SPACE`, `PAGE_NO`);

-- Page id:11, Found records: 2, Lost records: YES, Leaf page: YES

可以看到索引ID分别是 26 27

 

创建建表的文件  test6/a.sql test6/b.sql

开始恢复数据。

./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000000027.page -t test6/b.sql -odumps/b.dmmp -l dumps/b.sql

 

./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000000027.page -t test6/b.sql -odumps/b.dmmp -l dumps/b.sql

 

导入数据到数据库中

 

mysql>create database test6;

Query OK, 1row affected (0.00 sec)

 

mysql> usetest6;

Databasechanged

mysql>source test6/a.sql

Query OK, 0rows affected (0.07 sec)

 

mysql>source test6/b.sql

Query OK, 0rows affected (0.06 sec)

 

mysql>source dumps/a.sql

Query OK, 0rows affected (0.00 sec)

 

Query OK,1081922 rows affected (6.18 sec)

Records:1081922  Deleted: 0  Skipped: 0 Warnings: 0

 

mysql>source dumps/b.sql

Query OK, 0rows affected (0.00 sec)

 

Query OK, 2rows affected (0.07 sec)

Records:2  Deleted: 0  Skipped: 0 Warnings: 0

 

数据恢复成功

 

 

 

测试场景3 Drop Database (innodb_file_per_table=ON Windows平台)

我考虑到了另外一种情况,如果是windows平台下删除了数据库,是否有办法通过这个软件来读取呢,我们可以试一下

创建数据库和测试表

查看下innodb_file_per_table的值:

mysql> show variables like 'inno%per%tab%';

+-----------------------+-------+

| Variable_name         |Value |

+-----------------------+-------+

| innodb_file_per_table | ON   |

+-----------------------+-------+

1 row in set (0.00 sec)

 

创建测试用的数据库 test_recover和表a1

mysql> use test_recover;

Database changed

mysql> create table a1(a1 int,a2 int);

Query OK, 0 rows affected (0.40 sec)

 

mysql> insert into a1 values(1,2)

    -> ;

Query OK, 1 row affected (0.11 sec)

 

mysql> insert into a1 values(3,4)

    -> ;

Query OK, 1 row affected (0.08 sec)

 

mysql> commit;

Query OK, 0 rows affected (0.00 sec)

 

mysql> select * from a1;

+------+------+

| a1   | a2   |

+------+------+

|    1 |    2 |

|    3 |    4 |

+------+------+

2 rows in set (0.00 sec)

 

查看下我们的数据在哪个盘:

mysql> show variables like 'datadir';

+---------------+-----------------------------+

| Variable_name | Value                       |

+---------------+-----------------------------+

| datadir       |D:\MyTool\xampp\mysql\data\ |

+---------------+-----------------------------+

1 row in set (0.00 sec)

 

删除数据库

 

 

开始恢复数据

首先安装 Samba

yum install samba

 

因为我默认的administrator帐号没有密码,所以在windows上创建了一个用户 admin密码是 admin.

测试下帐号:

[root@centos~]# smbclient -L 10.0.0.4 -U admin

Enter admin'spassword:

Domain=[ACTION-PC]OS=[Windows 7 Ultimate 7601 Service Pack 1] Server=[Windows 7 Ultimate 6.1]

 

        Sharename       Type     Comment

        ---------       ----     -------

        ADMIN$          Disk      远程管理

        C$              Disk      默认共享

        D$              Disk      默认共享

        E$              Disk      默认共享

        F$              Disk      默认共享

        IPC$            IPC       远程 IPC

sessionrequest to 10.0.0.4 failed (Called name not present)

sessionrequest to 10 failed (Called name not present)

sessionrequest to *SMBSERVER failed (Called name not present)

NetBIOS overTCP disabled -- no workgroup available

 

创建 /d 目录,然后 D盘挂载到本地的 /d 目录下

[root@centos~]# mount -t cifs -o username=admin,password=admin   //10.0.0.4/d$ /d/

 

 

[root@centos~]# df -h

Filesystem            Size  Used Avail Use% Mounted on

/dev/mapper/vg_centos-lv_root

                       50G  4.2G  43G   9% /

tmpfs                 499M     0 499M   0% /dev/shm

/dev/sda1             477M   36M 416M   8% /boot

/dev/mapper/vg_centos-lv_home

                       47G   52M  45G   1% /home

//10.0.0.4/d$         101G  89G   12G  89% /d

 

尝试去恢复数据:

[root@centosundrop-for-innodb]#  ./stream_parser -f//10.0.0.4/d$ -t 101g

Opening file://10.0.0.4/d$

Fileinformation:

 

Errno = 2,Error = No such file or directory

All workersfinished in 0 sec

换个参数:

[root@centosundrop-for-innodb]#  ./stream_parser -f/d/ -t 101g

Opening file:/d

Fileinformation:

 

ID of devicecontaining file:           28

inodenumber:                 1407374883553285

protection:                          40755 (directory)

number of hardlinks:                    1

user ID ofowner:                        0

group ID ofowner:                       0

device ID (ifspecial file):             0

blocksize forfilesystem I/O:        16384

number ofblocks allocated:             80

time of lastaccess:            1449495079 MonDec  7 21:31:19 2015

time of lastmodification:      1449495079 MonDec  7 21:31:19 2015

time of laststatus change:     1449495079 MonDec  7 21:31:19 2015

total size, inbytes:                40960 (40.000 kiB)

 

Size toprocess:              108447924224(101.000 GiB)

Worker(0):Failed to read from disk: Is a directory

All workersfinished in 0 sec

 

最终都失败了。看来没有办法读取windows下的分区来恢复数据,不知道如果把物理磁盘挂载到Linux下会不会有效果。

 

测试场景4Drop Database (innodb_file_per_table=OFF Windows平台)

分区是无法读取了,但是文件或许可以,让我们再次测试下。

创建数据库和测试表

查看下innodb_file_per_table的值:

mysql> showvariables like 'inno%per%tab%';

+-----------------------+-------+

|Variable_name         | Value |

+-----------------------+-------+

| innodb_file_per_table| OFF    |

+-----------------------+-------+

1 row in set(0.00 sec)

 

创建测试用的数据库 test_recover2和表 a2

mysql>create database test_recover2;

Query OK, 1row affected (0.00 sec)

 

mysql> use test_recover2;

Databasechanged

mysql>create table a2(a1 int,a2 int);

Query OK, 0rows affected (0.40 sec)

 

mysql>insert into a2 values(1,2)

    -> ;

Query OK, 1row affected (0.06 sec)

 

mysql>insert into a2 values(3,4)

    -> ;

Query OK, 1row affected (0.04 sec)

 

mysql>insert into a2 values(5,6);

Query OK, 1row affected (0.06 sec)

 

mysql>commit;

Query OK, 0rows affected (0.00 sec)

 

mysql>select * from a2;

+------+------+

| a1   | a2  |

+------+------+

|    1 |   2 |

|    3 |   4 |

|    5 |   6 |

+------+------+

3 rows in set(0.00 sec)

 

查看下我们的数据在哪个盘:

mysql> showvariables like 'datadir';

+---------------+-----------------------------+

|Variable_name | Value                      |

+---------------+-----------------------------+

| datadir       | D:\MyTool\xampp\mysql\data\|

+---------------+-----------------------------+

1 row in set(0.00 sec)

 

删除数据库

 

开始恢复数据

D:\MyTool\xampp\mysql\data目录下的 ibdata1 文件上传到Linux服务器的/tmp目录下

开始恢复数据

[root@centosundrop-for-innodb]#  ./stream_parser -f/tmp/ibdata1

Opening file:/tmp/ibdata1

Fileinformation:

 

ID of devicecontaining file:        64768

inodenumber:                      2753060

protection:                         100644 (regular file)

number of hardlinks:                    1

user ID ofowner:                        0

group ID ofowner:                       0

device ID (ifspecial file):             0

blocksize forfilesystem I/O:         4096

number ofblocks allocated:         155648

time of lastaccess:            1436277889 TueJul  7 22:04:49 2015

time of lastmodification:      1449498101 MonDec  7 22:21:41 2015

time of laststatus change:     1449498181 MonDec  7 22:23:01 2015

total size, inbytes:             79691776 (76.000 MiB)

 

Size toprocess:                  79691776(76.000 MiB)

All workersfinished in 0 sec

 

然后解析文件,获取表的信息:

[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000001.page  -t ./dictionary/SYS_TABLES.sql  -o ./dumps/SYS_TABLES.dmp  -l ./dumps/SYS_TABLES.sql

 

[root@centosundrop-for-innodb]# cat ./dumps/SYS_TABLES.dmp | grep recover

000000055C05    05000002181423  SYS_TABLES      "test\_recover/a1"      1289   2       1       0      80      ""      1275

000000055C19    14000002042D29  SYS_TABLES      "test\_recover2/a2"     1290   2       1       0      64      ""      0

000000055C05    05000002181423  SYS_TABLES      "test\_recover/a1"      1289   2       1       0      80      ""      1275

000000055C19    14000002042D29  SYS_TABLES      "test\_recover2/a2"     1290   2       1       0      64      ""      0

这里我们发现了上一次测试场景里面的 test_recover.a1表的信息。我们这里可以一起尝试恢复下

test_recover.a1  1289

test_recover2.a21290

 

分别获取这2个表的索引信息:

[root@centosundrop-for-innodb]# ./c_parser -4Df ./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page  -t ./dictionary/SYS_INDEXES.sql | grep 1289

00000000CCD1    58000001FA2FC1  SYS_INDEXES     841    1289    "PRIMARY"       1      3       827     3

SETFOREIGN_KEY_CHECKS=0;

 

[root@centosundrop-for-innodb]# ./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page  -t ./dictionary/SYS_INDEXES.sql | grep 1290

000000055C19    14000002042C82  SYS_INDEXES     1290    1575    "GEN\_CLUST\_INDEX"     0      1       0       4294967295

00000000CCD8    5C0000025C1EBB  SYS_INDEXES     842    1290    "PRIMARY"       2      3       828     3

000000055C19    14000002042C82  SYS_INDEXES     1290   1575    "GEN\_CLUST\_INDEX"     0      1       0       4294967295

SETFOREIGN_KEY_CHECKS=0;

LOAD DATALOCAL INFILE '/root/undrop-for-innodb/dumps/default/SYS_INDEXES' REPLACE INTOTABLE `SYS_INDEXES` FIELDS TERMINATED BY '\t' OPTIONALLY ENCLOSED BY '"'LINES STARTING BY 'SYS_INDEXES\t' (`TABLE_ID`, `ID`, `NAME`, `N_FIELDS`,`TYPE`, `SPACE`, `PAGE_NO`);

 

可以看到,只有1290找到了索引的ID 1575 test_recover.a1确实无法恢复了。

 

创建建表的文件  test_recover2/a2.sql

开始恢复数据。

[root@centosundrop-for-innodb]# ./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000001575.page -t test_recover2/a2.sql -odumps/a2.dmmp -l dumps/a2.sql

[root@centosundrop-for-innodb]# cat dumps/a2.dmmp

-- Page id:336, Format: COMPACT, Records list: Valid, Expected records: (3 3)

000000003500    000000055C11    8E000001410110  a2     1       2

000000003501    000000055C12    8F000002750110  a2     3       4

000000003502    000000055C17    92000002760110  a2     5       6

-- Page id:336, Found records: 3, Lost records: NO, Leaf page: YES

-- Page id:336, Format: COMPACT, Records list: Valid, Expected records: (3 3)

000000003500    000000055C11    8E000001410110  a2     1       2

000000003501    000000055C12    8F000002750110  a2     3       4

000000003502    000000055C17    92000002760110  a2     5       6

-- Page id:336, Found records: 3, Lost records: NO, Leaf page: YES

[root@centosundrop-for-innodb]#

 

可以看到数据可以恢复。

剩下的步骤就都一样了,创建表,然后加载数据。

 

恢复数据总结

Linux 平台:  都可以恢复。

Windows平台: 如果 innodb_file_per_table=OFF,则可以恢复,否则无法恢复。

 

恢复步骤:

  1. stream_parser 工具恢复数据。

如果 innodb_file_per_table=OFF 所有数据在 ibdata1中,用下面的命令

./stream_parser-f /var/lib/mysql/ibdata1

如果innodb_file_per_table=ON 所有数据在数据目录下,用下面的命令:

./stream_parser -f /dev/mapper/vg_centos-lv_root -t 50g

需要用df查看到的逻辑卷的地址,并用-t 指定逻辑卷的大小。

 

运行完毕后,会在当前目录下生成一个pages-xxxxx 的目录。所有恢复出来的数据都在这个目录下。

 

  1. c_parser 来解析恢复出来的文件

  2. 0000000000000001.page 文件中是恢复出来的SYS_TABLES 的内容。

./c_parser -4Df ./pages-vg_centos-lv_root/FIL_PAGE_INDEX/0000000000000001.page -t ./dictionary/SYS_TABLES.sql  -o ./dumps/SYS_TABLES.dmp  -l ./dumps/SYS_TABLES.sql

查看SYS_TABLES.dmp ,找到需要恢复的表的ID

  1. page 文件中是恢复出来的 SYS_INDEXS的内容。

./c_parser -4Df./pages-ibdata1/FIL_PAGE_INDEX/0000000000000003.page  -t ./dictionary/SYS_INDEXES.sql

查看结果,筛选出所需要恢复表所对应的索引ID

 

  1. 恢复数据

找到000000[索引ID].page 文件,解析,前提是我们必须要有该表的建表语句

./c_parser -6f pages-ibdata1/FIL_PAGE_INDEX/0000000000000027.page -ttest6/b.sql -o dumps/b.dump -l dumps/b.sql

恢复出来的数据在.dump 文件中,运行 test6/b.sql 创建表(如果没有建表语句的话,可以通过其他方式获取,在别的文章里面会提到),然后运行dumps/b.sql 加载数据。

 

 

命令手册

C_Parser

[root@centos undrop-for-innodb]# ./c_parser -h

Error: Usage: ./c_parser -4|-5|-6 [-dDV] -f -t table.sql [-T N:M] [-b ]

  Where

    -f -- InnoDB page or directory with pages(all pages shouldhave same index_id)

    -t -- 将创建表的语句输出到table.sql 文件中

    -o -- Save dump in this file. Otherwise print to stdout

    -l -- Save SQL statements in this file. Otherwise print to stderr

    -h  -- Print this help

    -d  -- Process only those pages which potentiallycould have deleted records (default = NO)

    -D  -- 只恢复删除的数据(默认是No) (default = NO)

    -U  -- 只恢复没有删除的数据(默认是Yes) (default = YES)

    -V  -- Verbose mode (lots of debug information)

    -4  -- innodb_datafile is in REDUNDANT format

    -5  -- innodb_datafile is in COMPACT format

    -6  -- innodb_datafile is in MySQL 5.6 format

    -T  -- retrieves only pages with index id = NM (N- high word, M - low word of id)

    -b

-- Directory where external pages can be found. Usually it ispages-XXX/FIL_PAGE_TYPE_BLOB/

    -i -- Read external pages at their offsets from .

-p prefix -- Use prefix for a directoryname in LOAD DATA INFILE command

 

 

遇到的错误

Could not create directory

[root@centosundrop-for-innodb]# ./stream_parser -f /dev/mapper/vg_centos-lv_root -t 50g

Could notcreate directory pages-vg_centos-lv_root

mkdir(): File exists

如果看到这个错误,是因为已经存在 pages-vg_centos-lv_root这个目录了,只要删除这个目录就可以了。

 

Failed to parse tablestructure

[root@centos undrop-for-innodb]# ./c_parser -6fpages-ibdata1/FIL_PAGE_INDEX/0000000000000026.page -t test6/a.sql -odumps/a.dmmp -l dumps/a.sql

Line 2: syntax error at ''

 1: create tablea(id int)

 

 2:

Failed to parse table structure

 

这个错误是因为最后少了一个分号