fil0fil.c:

  Add fault tolerance in the scan of .ibd files at a crash recovery; formerly a single failure of readdir_get_next caused the rest of the directory to be skipped
parent 3dbbb2fc
...@@ -2924,6 +2924,44 @@ func_exit: ...@@ -2924,6 +2924,44 @@ func_exit:
mem_free(filepath); mem_free(filepath);
} }
/***************************************************************************
A fault-tolerant function that tries to read the next file name in the
directory. We retry 100 times if os_file_readdir_next_file() returns -1. The
idea is to read as much good data as we can and jump over bad data. */
static
int
fil_file_readdir_next_file(
/*=======================*/
/* out: 0 if ok, -1 if error even after the
retries, 1 if at the end of the directory */
ulint* err, /* out: this is set to DB_ERROR if an error
was encountered, otherwise not changed */
const char* dirname,/* in: directory name or path */
os_file_dir_t dir, /* in: directory stream */
os_file_stat_t* info) /* in/out: buffer where the info is returned */
{
ulint i;
int ret;
for (i = 0; i < 100; i++) {
ret = os_file_readdir_next_file(dirname, dir, info);
if (ret != -1) {
return(ret);
}
fprintf(stderr,
"InnoDB: Error: os_file_readdir_next_file() returned -1 in\n"
"InnoDB: directory %s\n"
"InnoDB: Crash recovery may have failed for some .ibd files!\n", dirname);
*err = DB_ERROR;
}
return(-1);
}
/************************************************************************ /************************************************************************
At the server startup, if we need crash recovery, scans the database At the server startup, if we need crash recovery, scans the database
directories under the MySQL datadir, looking for .ibd files. Those files are directories under the MySQL datadir, looking for .ibd files. Those files are
...@@ -2944,6 +2982,7 @@ fil_load_single_table_tablespaces(void) ...@@ -2944,6 +2982,7 @@ fil_load_single_table_tablespaces(void)
os_file_dir_t dbdir; os_file_dir_t dbdir;
os_file_stat_t dbinfo; os_file_stat_t dbinfo;
os_file_stat_t fileinfo; os_file_stat_t fileinfo;
ulint err = DB_SUCCESS;
/* The datadir of MySQL is always the default directory of mysqld */ /* The datadir of MySQL is always the default directory of mysqld */
...@@ -2959,7 +2998,7 @@ fil_load_single_table_tablespaces(void) ...@@ -2959,7 +2998,7 @@ fil_load_single_table_tablespaces(void)
/* Scan all directories under the datadir. They are the database /* Scan all directories under the datadir. They are the database
directories of MySQL. */ directories of MySQL. */
ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, dir, ret = fil_file_readdir_next_file(&err, fil_path_to_mysql_datadir, dir,
&dbinfo); &dbinfo);
while (ret == 0) { while (ret == 0) {
ulint len; ulint len;
...@@ -2997,7 +3036,7 @@ fil_load_single_table_tablespaces(void) ...@@ -2997,7 +3036,7 @@ fil_load_single_table_tablespaces(void)
/* We found a database directory; loop through it, /* We found a database directory; loop through it,
looking for possible .ibd files in it */ looking for possible .ibd files in it */
ret = os_file_readdir_next_file(dbpath, dbdir, ret = fil_file_readdir_next_file(&err, dbpath, dbdir,
&fileinfo); &fileinfo);
while (ret == 0) { while (ret == 0) {
/* printf( /* printf(
...@@ -3019,36 +3058,29 @@ fil_load_single_table_tablespaces(void) ...@@ -3019,36 +3058,29 @@ fil_load_single_table_tablespaces(void)
dbinfo.name, fileinfo.name); dbinfo.name, fileinfo.name);
} }
next_file_item: next_file_item:
ret = os_file_readdir_next_file(dbpath, dbdir, ret = fil_file_readdir_next_file(&err,
dbpath, dbdir,
&fileinfo); &fileinfo);
} }
if (0 != os_file_closedir(dbdir)) { if (0 != os_file_closedir(dbdir)) {
fputs( fputs(
"InnoDB: Warning: could not close database directory ", stderr); "InnoDB: Warning: could not close database directory ", stderr);
ut_print_filename(stderr, dbpath); ut_print_filename(stderr, dbpath);
putc('\n', stderr); putc('\n', stderr);
err = DB_ERROR;
} }
} }
next_datadir_item: next_datadir_item:
ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, ret = fil_file_readdir_next_file(&err,
fil_path_to_mysql_datadir,
dir, &dbinfo); dir, &dbinfo);
} }
mem_free(dbpath); mem_free(dbpath);
/* At the end of directory we should get 1 as the return value, -1
if there was an error */
if (ret != 1) {
fprintf(stderr,
"InnoDB: Error: os_file_readdir_next_file returned %d in MySQL datadir\n",
ret);
os_file_closedir(dir);
return(DB_ERROR);
}
if (0 != os_file_closedir(dir)) { if (0 != os_file_closedir(dir)) {
fprintf(stderr, fprintf(stderr,
"InnoDB: Error: could not close MySQL datadir\n"); "InnoDB: Error: could not close MySQL datadir\n");
...@@ -3056,7 +3088,7 @@ next_datadir_item: ...@@ -3056,7 +3088,7 @@ next_datadir_item:
return(DB_ERROR); return(DB_ERROR);
} }
return(DB_SUCCESS); return(err);
} }
/************************************************************************ /************************************************************************
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment