从ibd文件获取表空间id

xtrabackup恢复过程中出现如下错误 

InnoDB: Doing recovery: scanned up to log sequence number 1024370417664 (62 %)
InnoDB: Doing recovery: scanned up to log sequence number 1024375660544 (75 %)
140810 13:53:42  InnoDB: Starting an apply batch of log records to the database...
InnoDB: Progress in percents: 140810 13:53:42  InnoDB: Error: space id and page n:o stored in the page
InnoDB: read in are 1571195158:1995475462, should be 51:8406774!
InnoDB: Database page corruption on disk or a failed
InnoDB: file read of page 8406774.
InnoDB: You may have to recover from a backup.
140810 13:53:42  InnoDB: Page dump in ascii and hex (16384 bytes):

从错误信息中可以看出,有页损坏了,并给出了space id和page no (51,8406774). 

在非共享表空间(即innodb_file_per_table=on)时,每个表对应一个表空间。那么我们怎么通过表空间id(即space id)得到对应的表呢?

在mysql 5.6以上版本中,可通过查询information_schema.INNODB_SYS_DATAFILES得到表空间id和表的对应关系,

http://dev.mysql.com/doc/refman/5.6/en/innodb-sys-datafiles-table.html 

mysql> select * from information_schema.INNODB_SYS_DATAFILES where space=287;
+-------+---------------+
| SPACE | PATH          |
+-------+---------------+
|   287 | .\test\t2.ibd |
+-------+---------------+

然而出现此问题的mysql版本为5.1.那么我们怎么得到5.6以下版本表空间id和表的对应关系呢。

从源码中可以看到,每个表空间第一个页的偏移38字节处,用4个字节存储了表空间id信息。参看函数fsp_header_init_fields

于是写了个小工具直接从idb文件读取表空间id信息。

例如获取表t1的表空间为795 

$ sudo ./test /u01/mysql/data/test/t1.ibd
spaceid:795 , file:/u01/mysql/data/test/t1.ibd 

工具源码如下:

#include "stdlib.h"
#include "stdio.h"

#ifdef _WIN64
typedef unsigned __int64     ulint;
#else
typedef unsigned long int     ulint;

#endif /* _WIN64 */

typedef unsigned char byte;

ulint
mach_read_from_4(
     byte*     b)     /*!< in: pointer to four bytes */
{
     return( ((ulint)(b[0]) << 24)
          | ((ulint)(b[1]) << 16)
          | ((ulint)(b[2]) << 8)
          | (ulint)(b[3])
          );
}

void main(int argc,char *argv[])
{
        FILE *fp;
        byte ret[5];
        int  offset;
        ulint spaceid;

        if ((fp=fopen(argv[1],"r"))==NULL)
        {
                printf("cannot open this file\n");
                exit(0);
        }

        offset=38;
        if (fseek(fp,offset,0)!=0)
        {
                printf("cannot move pointer there.\n");
                exit(0);
        }

        fread(ret,sizeof(byte),4,fp);
        spaceid = mach_read_from_4(ret);

        printf("spaceid:%lu , file:%s\n",spaceid,argv[1]);

        fclose(fp);
}

 

posted @ 2014-08-10 18:21  sstrive  阅读(3602)  评论(0编辑  收藏  举报