Commit 69dbdde1 authored by unknown's avatar unknown

Many files:

  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation


innobase/buf/buf0buf.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/dict/dict0crea.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/dict/dict0dict.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/fil/fil0fil.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/fsp/fsp0fsp.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/fil0fil.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/fsp0fsp.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/log0recv.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/mtr0log.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/mtr0mtr.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/os0file.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/ut0dbg.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/ut0ut.h:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/ha0ha.ic:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/include/mtr0log.ic:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/log/log0log.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/log/log0recv.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/mem/mem0pool.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/os/os0file.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/pars/lexyy.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/row/row0mysql.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/row/row0sel.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/srv/srv0srv.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/srv/srv0start.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/ut/ut0rnd.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
innobase/ut/ut0ut.c:
  Merge with ibbackup; bug fix: .ibd files were extended 2 x the required amount; InnoDB does not create the small file inno_arch_log... any more at database creation
parent 32c22ce2
......@@ -297,8 +297,9 @@ buf_page_is_corrupted(
ulint old_checksum;
ulint checksum_field;
ulint old_checksum_field;
#ifndef UNIV_HOTBACKUP
dulint current_lsn;
#endif
if (mach_read_from_4(read_buf + FIL_PAGE_LSN + 4)
!= mach_read_from_4(read_buf + UNIV_PAGE_SIZE
- FIL_PAGE_END_LSN_OLD_CHKSUM + 4)) {
......
......@@ -302,8 +302,11 @@ dict_build_table_def_step(
- page 3 will contain the root of the clustered index of the
table we create here. */
table->space = 0; /* reset to zero for the call below */
error = fil_create_new_single_table_tablespace(
&(table->space), table->name, 4);
&(table->space), table->name,
FIL_IBD_FILE_INITIAL_SIZE);
if (error != DB_SUCCESS) {
return(error);
......@@ -311,7 +314,7 @@ dict_build_table_def_step(
mtr_start(&mtr);
fsp_header_init(table->space, 4, &mtr);
fsp_header_init(table->space, FIL_IBD_FILE_INITIAL_SIZE, &mtr);
mtr_commit(&mtr);
}
......
......@@ -2580,7 +2580,7 @@ dict_create_foreign_constraints_low(
sprintf(buf + strlen(buf),
" Error in foreign key constraint of table %.500s.\n"
"Cannot find the table from the internal data dictionary of InnoDB.\n"
"Create table statement:\n%.2000\n", name, sql_string);
"Create table statement:\n%.2000s\n", name, sql_string);
ut_a(strlen(buf) < DICT_FOREIGN_ERR_BUF_LEN);
mutex_exit(&dict_foreign_err_mutex);
......
......@@ -23,6 +23,9 @@ Created 10/25/1995 Heikki Tuuri
#include "fsp0fsp.h"
#include "srv0srv.h"
#include "srv0start.h"
#include "mtr0mtr.h"
#include "mtr0log.h"
/*
IMPLEMENTATION OF THE TABLESPACE MEMORY CACHE
......@@ -80,6 +83,10 @@ out of the LRU-list and keep a count of pending operations. When an operation
completes, we decrement the count and return the file node to the LRU-list if
the count drops to zero. */
/* When mysqld is run, the default directory "." is the mysqld datadir,
but in ibbackup we must set it explicitly */
char* fil_path_to_mysql_datadir = (char*)".";
ulint fil_n_pending_log_flushes = 0;
ulint fil_n_pending_tablespace_flushes = 0;
......@@ -257,6 +264,17 @@ fil_node_complete_io(
ulint type); /* in: OS_FILE_WRITE or OS_FILE_READ; marks
the node as modified if
type == OS_FILE_WRITE */
/***********************************************************************
Checks if a single-table tablespace for a given table name exists in the
tablespace memory cache. */
static
ulint
fil_get_space_id_for_table(
/*=======================*/
/* out: space id, ULINT_UNDEFINED if not
found */
char* name); /* in: table name in the standard
'databasename/tablename' format */
/***********************************************************************
......@@ -474,15 +492,18 @@ fil_node_open_file(
system->n_open++;
if (node->size == 0) {
/* It must be a single-table tablespace and we do not know the
size of the file yet */
ut_a(space->id != 0);
os_file_get_size(node->handle, &size_low, &size_high);
size_bytes = (((ib_longlong)size_high) << 32)
+ (ib_longlong)size_low;
#ifdef UNIV_HOTBACKUP
node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE);
#else
/* It must be a single-table tablespace and we do not know the
size of the file yet */
ut_a(space->id != 0);
if (size_bytes >= FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) {
node->size = (ulint) ((size_bytes / (1024 * 1024))
......@@ -490,8 +511,8 @@ fil_node_open_file(
} else {
node->size = (ulint) (size_bytes / UNIV_PAGE_SIZE);
}
space->size = node->size;
#endif
space->size += node->size;
}
if (space->purpose == FIL_TABLESPACE && space->id != 0) {
......@@ -516,6 +537,7 @@ fil_node_close_file(
ut_a(node->open);
ut_a(node->n_pending == 0);
ut_a(node->n_pending_flushes == 0);
ut_a(node->modification_counter == node->flush_counter);
ret = os_file_close(node->handle);
ut_a(ret);
......@@ -690,12 +712,13 @@ fil_mutex_enter_and_prepare_for_io(
mutex_exit(&(system->mutex));
#ifndef UNIV_HOTBACKUP
/* Wake the i/o-handler threads to make sure pending i/o's are
performed */
os_aio_simulated_wake_handler_threads();
os_thread_sleep(20000);
#endif
/* Flush tablespaces so that we can close modified files in the LRU
list */
......@@ -722,6 +745,11 @@ fil_node_free(
ut_a(node->n_pending == 0);
if (node->open) {
/* We fool the assertion in fil_node_close_file() to think
there are no unflushed modifications in the file */
node->modification_counter = node->flush_counter;
fil_node_close_file(node, system);
}
......@@ -854,8 +882,7 @@ fil_space_create(
space->id = id;
system->tablespace_version++;
space->tablespace_version =
system->tablespace_version;
space->tablespace_version = system->tablespace_version;
space->mark = FALSE;
if (purpose == FIL_TABLESPACE && id > system->max_assigned_id) {
......@@ -1005,6 +1032,29 @@ fil_space_free(
return(TRUE);
}
#ifdef UNIV_HOTBACKUP
/***********************************************************************
Returns the tablespace object for a given id, or NULL if not found from the
tablespace memory cache. */
static
fil_space_t*
fil_get_space_for_id_low(
/*=====================*/
/* out: tablespace object or NULL; NOTE that you must
own &(fil_system->mutex) to call this function! */
ulint id) /* in: space id */
{
fil_system_t* system = fil_system;
fil_space_t* space;
ut_ad(system);
HASH_SEARCH(hash, system->spaces, id, space, space->id == id);
return(space);
}
#endif
/***********************************************************************
Returns the size of the space in pages. The tablespace must be cached in the
memory cache. */
......@@ -1456,6 +1506,225 @@ fil_decr_pending_ibuf_merges(
mutex_exit(&(system->mutex));
}
/************************************************************
Creates the database directory for a table if it does not exist yet. */
static
void
fil_create_directory_for_tablename(
/*===============================*/
char* name) /* in: name in the standard 'databasename/tablename'
format */
{
char* ptr;
char path[OS_FILE_MAX_PATH];
sprintf(path, "%s/%s", fil_path_to_mysql_datadir, name);
ptr = path + ut_strlen(path);
while (*ptr != '/') {
ptr--;
ut_a(ptr >= path);
}
*ptr = '\0';
srv_normalize_path_for_win(path);
ut_a(os_file_create_directory(path, FALSE));
}
#ifndef UNIV_HOTBACKUP
/************************************************************
Writes a log record about an .ibd file create/rename/delete. */
static
void
fil_op_write_log(
/*=============*/
ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or
MLOG_FILE_RENAME */
ulint space_id, /* in: space id */
char* name, /* in: table name in the familiar
'databasename/tablename' format, or the file
path in the case of MLOG_FILE_DELETE */
char* new_name, /* in: if type is MLOG_FILE_RENAME, the new
table name in the 'databasename/tablename'
format */
mtr_t* mtr) /* in: mini-transaction handle */
{
byte* log_ptr;
log_ptr = mlog_open(mtr, 30);
log_ptr = mlog_write_initial_log_record_for_file_op(type, space_id, 0,
log_ptr, mtr);
/* Let us store the strings as null-terminated for easier readability
and handling */
mach_write_to_2(log_ptr, ut_strlen(name) + 1);
log_ptr += 2;
mlog_close(mtr, log_ptr);
mlog_catenate_string(mtr, name, ut_strlen(name) + 1);
if (type == MLOG_FILE_RENAME) {
log_ptr = mlog_open(mtr, 30);
mach_write_to_2(log_ptr, ut_strlen(new_name) + 1);
log_ptr += 2;
mlog_close(mtr, log_ptr);
mlog_catenate_string(mtr, new_name, ut_strlen(new_name) + 1);
}
}
#endif
/***********************************************************************
Parses the body of a log record written about an .ibd file operation. That is,
the log record part after the standard (type, space id, page no) header of the
log record.
If desired, also replays the delete or rename operation if the .ibd file
exists and the space id in it matches. Replays the create operation if a file
at that path does not exist yet. If the database directory for the file to be
created does not exist, then we create the directory, too.
Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the
datadir that we should use in replaying the file operations. */
byte*
fil_op_log_parse_or_replay(
/*=======================*/
/* out: end of log record, or NULL if the
record was not completely contained between
ptr and end_ptr */
byte* ptr, /* in: buffer containing the log record body,
or an initial segment of it, if the record does
not fir completely between ptr and end_ptr */
byte* end_ptr, /* in: buffer end */
ulint type, /* in: the type of this log record */
ibool do_replay, /* in: TRUE if we want to replay the
operation, and not just parse the log record */
ulint space_id) /* in: if do_replay is TRUE, the space id of
the tablespace in question; otherwise
ignored */
{
ulint name_len;
ulint new_name_len;
char* name;
char* new_name = NULL;
if (end_ptr < ptr + 2) {
return(NULL);
}
name_len = mach_read_from_2(ptr);
ptr += 2;
if (end_ptr < ptr + name_len) {
return(NULL);
}
name = ptr;
ptr += name_len;
if (type == MLOG_FILE_RENAME) {
if (end_ptr < ptr + 2) {
return(NULL);
}
new_name_len = mach_read_from_2(ptr);
ptr += 2;
if (end_ptr < ptr + new_name_len) {
return(NULL);
}
new_name = ptr;
ptr += new_name_len;
}
/* We managed to parse a full log record body */
/*
printf("Parsed log rec of type %lu space %lu\n"
"name %s\n", type, space_id, name);
if (type == MLOG_FILE_RENAME) {
printf("new name %s\n", new_name);
}
*/
if (do_replay == FALSE) {
return(ptr);
}
/* Let us try to perform the file operation, if sensible. Note that
ibbackup has at this stage already read in all space id info to the
fil0fil.c data structures.
NOTE that our algorithm is not guaranteed to work correctly if there
were renames of tables during the backup. See ibbackup code for more
on the problem. */
if (type == MLOG_FILE_DELETE) {
if (fil_tablespace_exists_in_mem(space_id)) {
ut_a(fil_delete_tablespace(space_id));
}
} else if (type == MLOG_FILE_RENAME) {
if (fil_get_space_id_for_table(name) == space_id) {
/* Create the database directory for the new name, if
it does not exist yet */
fil_create_directory_for_tablename(new_name);
/* Rename the table if there is not yet a tablespace
with the same name */
if (fil_get_space_id_for_table(new_name)
== ULINT_UNDEFINED) {
ut_a(fil_rename_tablespace(name, space_id,
new_name));
} else {
fprintf(stderr,
"InnoDB: Warning: in log replay cannot rename tablespace\n"
"InnoDB: %s with id %lu to %s, because it exists already.\n",
name, space_id, new_name);
}
}
} else {
ut_a(type == MLOG_FILE_CREATE);
if (fil_tablespace_exists_in_mem(space_id)) {
/* Do nothing */
} else if (fil_get_space_id_for_table(name) !=
ULINT_UNDEFINED) {
/* Do nothing */
} else {
/* Create the database directory for name, if it does
not exist yet */
fil_create_directory_for_tablename(name);
ut_a(space_id != 0);
ut_a(DB_SUCCESS ==
fil_create_new_single_table_tablespace(
&space_id, name,
FIL_IBD_FILE_INITIAL_SIZE));
}
}
return(ptr);
}
/***********************************************************************
Deletes a single-table tablespace. The tablespace must be cached in the
memory cache. */
......@@ -1554,7 +1823,7 @@ fil_delete_tablespace(
}
mutex_exit(&(system->mutex));
#ifndef UNIV_HOTBACKUP
/* Invalidate in the buffer pool all pages belonging to the
tablespace. Since we have set space->is_being_deleted = TRUE, readahead
or ibuf merge can no longer read more pages of this tablespace to the
......@@ -1563,6 +1832,8 @@ fil_delete_tablespace(
fil_flush() from being applied to this tablespace. */
buf_LRU_invalidate_tablespace(id);
#endif
/* printf("Deleting tablespace %s id %lu\n", space->name, id); */
success = fil_space_free(id);
......@@ -1570,7 +1841,23 @@ fil_delete_tablespace(
success = os_file_delete(path);
if (success) {
/* Write a log record about the deletion of the .ibd
file, so that ibbackup can replay it in the
--apply-log phase. We use a dummy mtr and the familiar
log write mechanism. */
#ifndef UNIV_HOTBACKUP
{
mtr_t mtr;
/* When replaying the operation in ibbackup, do not try
to write any log record */
mtr_start(&mtr);
fil_op_write_log(MLOG_FILE_DELETE, id, path,
NULL, &mtr);
mtr_commit(&mtr);
}
#endif
return(TRUE);
}
}
......@@ -1679,8 +1966,8 @@ fil_rename_tablespace(
fil_space_t* space;
fil_node_t* node;
ulint count = 0;
char* path = NULL;
char old_path[OS_FILE_MAX_PATH];
char path[OS_FILE_MAX_PATH];
ut_a(id != 0);
retry:
......@@ -1752,9 +2039,10 @@ fil_rename_tablespace(
/* Check that the old name in the space is right */
ut_a(strlen(old_name) < OS_FILE_MAX_PATH - 10);
ut_a(strlen(old_name) + strlen(fil_path_to_mysql_datadir)
< OS_FILE_MAX_PATH - 10);
sprintf(old_path, "./%s.ibd", old_name);
sprintf(old_path, "%s/%s.ibd", fil_path_to_mysql_datadir, old_name);
srv_normalize_path_for_win(old_path);
......@@ -1763,9 +2051,11 @@ fil_rename_tablespace(
/* Rename the tablespace and the node in the memory cache */
ut_a(strlen(new_name) < OS_FILE_MAX_PATH - 10);
ut_a(strlen(new_name) + strlen(fil_path_to_mysql_datadir)
< OS_FILE_MAX_PATH - 10);
path = mem_alloc(OS_FILE_MAX_PATH);
sprintf(path, "./%s.ibd", new_name);
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, new_name);
srv_normalize_path_for_win(path);
......@@ -1776,6 +2066,8 @@ fil_rename_tablespace(
goto func_exit;
}
/* printf("Renaming tablespace %s to %s id %lu\n", path, old_path, id);
*/
success = os_file_rename(old_path, path);
if (!success) {
......@@ -1784,11 +2076,26 @@ fil_rename_tablespace(
ut_a(fil_rename_tablespace_in_mem(space, node, old_path));
}
func_exit:
if (path) {
mem_free(path);
}
space->stop_ios = FALSE;
mutex_exit(&(system->mutex));
#ifndef UNIV_HOTBACKUP
if (success) {
mtr_t mtr;
mtr_start(&mtr);
fil_op_write_log(MLOG_FILE_RENAME, id, old_name, new_name,
&mtr);
mtr_commit(&mtr);
}
#endif
return(success);
}
......@@ -1802,11 +2109,14 @@ ulint
fil_create_new_single_table_tablespace(
/*===================================*/
/* out: DB_SUCCESS or error code */
ulint* space_id, /* out: space id */
ulint* space_id, /* in/out: space id; if this is != 0, then
this is an input parameter, otherwise
output */
char* tablename, /* in: the table name in the usual
databasename/tablename format of InnoDB */
ulint size) /* in: the initial size of the tablespace file
in pages, must be > 0 */
in pages, must be >= FIL_IBD_FILE_INITIAL_SIZE
*/
{
os_file_t file;
ibool ret;
......@@ -1815,9 +2125,11 @@ fil_create_new_single_table_tablespace(
ibool success;
char path[OS_FILE_MAX_PATH];
ut_a(strlen(tablename) < OS_FILE_MAX_PATH - 10);
ut_a(size >= FIL_IBD_FILE_INITIAL_SIZE);
sprintf(path, "./%s.ibd", tablename);
ut_a(strlen(tablename) + strlen(fil_path_to_mysql_datadir)
< OS_FILE_MAX_PATH - 10);
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, tablename);
srv_normalize_path_for_win(path);
......@@ -1865,7 +2177,11 @@ fil_create_new_single_table_tablespace(
return(DB_OUT_OF_FILE_SPACE);
}
if (*space_id == 0) {
*space_id = fil_assign_new_space_id();
}
/* printf("Creating tablespace %s id %lu\n", path, *space_id); */
if (*space_id == ULINT_UNDEFINED) {
ut_free(page);
......@@ -1934,6 +2250,17 @@ fil_create_new_single_table_tablespace(
fil_node_create(path, size, *space_id, FALSE);
#ifndef UNIV_HOTBACKUP
{
mtr_t mtr;
mtr_start(&mtr);
fil_op_write_log(MLOG_FILE_CREATE, *space_id, tablename, NULL, &mtr);
mtr_commit(&mtr);
}
#endif
return(DB_SUCCESS);
}
......@@ -1971,7 +2298,7 @@ fil_reset_too_high_lsns(
ut_a(strlen(name) < OS_FILE_MAX_PATH - 10);
sprintf(filepath, "./%s.ibd", name);
sprintf(filepath, "%s/%s.ibd", fil_path_to_mysql_datadir, name);
srv_normalize_path_for_win(filepath);
......@@ -2106,7 +2433,7 @@ fil_open_single_table_tablespace(
ut_a(strlen(name) < OS_FILE_MAX_PATH - 10);
sprintf(filepath, "./%s.ibd", name);
sprintf(filepath, "%s/%s.ibd", fil_path_to_mysql_datadir, name);
srv_normalize_path_for_win(filepath);
......@@ -2196,13 +2523,16 @@ fil_load_single_table_tablespace(
ulint size_low;
ulint size_high;
ib_longlong size;
#ifdef UNIV_HOTBACKUP
fil_space_t* space;
#endif
filepath = ut_malloc(OS_FILE_MAX_PATH);
ut_a(strlen(dbname) + strlen(filename) < OS_FILE_MAX_PATH - 10);
sprintf(filepath, "./%s/%s", dbname, filename);
ut_a(strlen(dbname) + strlen(filename)
+ strlen(fil_path_to_mysql_datadir) < OS_FILE_MAX_PATH - 100);
sprintf(filepath, "%s/%s/%s", fil_path_to_mysql_datadir, dbname,
filename);
srv_normalize_path_for_win(filepath);
file = os_file_create_simple_no_error_handling(filepath, OS_FILE_OPEN,
......@@ -2236,9 +2566,12 @@ fil_load_single_table_tablespace(
return;
}
size = (((ib_longlong)size_high) << 32) + (ib_longlong)size_low;
/* Every .ibd file is created >= 4 pages in size. Smaller files
cannot be ok. */
if (size < 4 * UNIV_PAGE_SIZE) {
size = (((ib_longlong)size_high) << 32) + (ib_longlong)size_low;
#ifndef UNIV_HOTBACKUP
if (size < FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
fprintf(stderr,
"InnoDB: Error: the size of single-table tablespace file %s\n"
"InnoDB: is only %lu %lu, should be at least %lu!", filepath, size_high,
......@@ -2248,24 +2581,95 @@ fil_load_single_table_tablespace(
return;
}
/* Read the first page of the tablespace */
#endif
/* Read the first page of the tablespace if the size big enough */
page = ut_malloc(UNIV_PAGE_SIZE);
if (size >= FIL_IBD_FILE_INITIAL_SIZE * UNIV_PAGE_SIZE) {
success = os_file_read(file, page, 0, 0, UNIV_PAGE_SIZE);
/* We have to read the tablespace id from the file */
space_id = fsp_header_get_space_id(page);
} else {
space_id = ULINT_UNDEFINED;
}
#ifndef UNIV_HOTBACKUP
if (space_id == ULINT_UNDEFINED || space_id == 0) {
fprintf(stderr,
"InnoDB: Error: tablespace id %lu in file %s is not sensible\n", space_id,
filepath);
goto func_exit;
}
#else
if (space_id == ULINT_UNDEFINED || space_id == 0) {
char* new_path;
fprintf(stderr,
"InnoDB: Renaming tablespace %s of id %lu,\n"
"InnoDB: to %s_ibbackup_old_vers_<timestamp>\n"
"InnoDB: because its size %lld is too small (< 4 pages 16 kB each),\n"
"InnoDB: or the space id in the file header is not sensible.\n"
"InnoDB: This can happen in an ibbackup run, and is not dangerous.\n",
filepath, space_id, filepath, size);
os_file_close(file);
new_path = ut_malloc(OS_FILE_MAX_PATH);
sprintf(new_path, "%s_ibbackup_old_vers_", filepath);
ut_sprintf_timestamp_without_extra_chars(
new_path + ut_strlen(new_path));
ut_a(os_file_rename(filepath, new_path));
ut_free(page);
ut_free(filepath);
ut_free(new_path);
return;
}
/* A backup may contain the same space several times, if the space got
renamed at a sensitive time. Since it is enough to have one version of
the space, we rename the file if a space with the same space id
already exists in the tablespace memory cache. We rather rename the
file than delete it, because if there is a bug, we do not want to
destroy valuable data. */
mutex_enter(&(fil_system->mutex));
space = fil_get_space_for_id_low(space_id);
if (space) {
char* new_path;
fprintf(stderr,
"InnoDB: Renaming tablespace %s of id %lu,\n"
"InnoDB: to %s_ibbackup_old_vers_<timestamp>\n"
"InnoDB: because space %s with the same id\n"
"InnoDB: was scanned earlier. This can happen if you have renamed tables\n"
"InnoDB: during an ibbackup run.\n", filepath, space_id, filepath,
space->name);
os_file_close(file);
new_path = ut_malloc(OS_FILE_MAX_PATH);
sprintf(new_path, "%s_ibbackup_old_vers_", filepath);
ut_sprintf_timestamp_without_extra_chars(
new_path + ut_strlen(new_path));
mutex_exit(&(fil_system->mutex));
ut_a(os_file_rename(filepath, new_path));
ut_free(page);
ut_free(filepath);
ut_free(new_path);
return;
}
mutex_exit(&(fil_system->mutex));
#endif
success = fil_space_create(filepath, space_id, FIL_TABLESPACE);
if (!success) {
......@@ -2305,7 +2709,7 @@ fil_load_single_table_tablespaces(void)
/* The datadir of MySQL is always the default directory of mysqld */
dir = os_file_opendir((char*)".", TRUE);
dir = os_file_opendir(fil_path_to_mysql_datadir, TRUE);
if (dir == NULL) {
......@@ -2317,8 +2721,8 @@ fil_load_single_table_tablespaces(void)
/* Scan all directories under the datadir. They are the database
directories of MySQL. */
ret = os_file_readdir_next_file((char*)".", dir, &dbinfo);
ret = os_file_readdir_next_file(fil_path_to_mysql_datadir, dir,
&dbinfo);
while (ret == 0) {
/* printf("Looking at %s in datadir\n", dbinfo.name); */
......@@ -2333,8 +2737,8 @@ fil_load_single_table_tablespaces(void)
ut_a(strlen(dbinfo.name) < OS_FILE_MAX_PATH - 10);
sprintf(dbpath, "./%s", dbinfo.name);
sprintf(dbpath, "%s/%s", fil_path_to_mysql_datadir,
dbinfo.name);
srv_normalize_path_for_win(dbpath);
dbdir = os_file_opendir(dbpath, FALSE);
......@@ -2378,7 +2782,8 @@ fil_load_single_table_tablespaces(void)
}
next_datadir_item:
ret = os_file_readdir_next_file((char*)".", dir, &dbinfo);
ret = os_file_readdir_next_file(fil_path_to_mysql_datadir,
dir, &dbinfo);
}
ut_free(dbpath);
......@@ -2427,11 +2832,10 @@ fil_print_orphaned_tablespaces(void)
&& !space->mark) {
fprintf(stderr,
"InnoDB: Warning: tablespace %s of id %lu has no matching table in\n"
"InnoDB: the InnoDB data dixtionary.\n", space->name, space->id);
"InnoDB: the InnoDB data dictionary.\n", space->name, space->id);
}
space = UT_LIST_GET_NEXT(space_list, space);
}
mutex_exit(&(system->mutex));
......@@ -2515,8 +2919,8 @@ there may be many tablespaces which are not yet in the memory cache. */
ibool
fil_space_for_table_exists_in_mem(
/*==============================*/
/* out: TRUE if a matching tablespace
exists in the memory cache */
/* out: TRUE if a matching tablespace exists
in the memory cache */
ulint id, /* in: space id */
char* name, /* in: table name in the standard
'databasename/tablename' format */
......@@ -2539,7 +2943,7 @@ fil_space_for_table_exists_in_mem(
mutex_enter(&(system->mutex));
sprintf(path, "./%s.ibd", name);
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, name);
srv_normalize_path_for_win(path);
/* Look if there is a space with the same id */
......@@ -2552,8 +2956,9 @@ fil_space_for_table_exists_in_mem(
HASH_SEARCH(name_hash, system->name_hash,
ut_fold_string(path), namespace,
0 == strcmp(namespace->name, path));
if (!print_error_if_does_not_exist) {
if (space && space == namespace) {
/* Found */
if (mark_space) {
space->mark = TRUE;
}
......@@ -2563,6 +2968,8 @@ fil_space_for_table_exists_in_mem(
return(TRUE);
}
if (!print_error_if_does_not_exist) {
mutex_exit(&(system->mutex));
return(FALSE);
......@@ -2602,7 +3009,8 @@ fil_space_for_table_exists_in_mem(
" InnoDB: Error: table %s\n"
"InnoDB: in InnoDB data dictionary has tablespace id %lu,\n"
"InnoDB: but tablespace with that id has name %s.\n"
"InnoDB: Have you deleted or moved .ibd files?", name, id, space->name);
"InnoDB: Have you deleted or moved .ibd files?\n", name, id, space->name);
if (namespace != NULL) {
fprintf(stderr,
"InnoDB: There is a tablespace with the right name\n"
......@@ -2618,43 +3026,78 @@ fil_space_for_table_exists_in_mem(
return(FALSE);
}
ut_a(space == namespace);
mutex_exit(&(system->mutex));
if (mark_space) {
space->mark = TRUE;
return(FALSE);
}
/***********************************************************************
Checks if a single-table tablespace for a given table name exists in the
tablespace memory cache. */
static
ulint
fil_get_space_id_for_table(
/*=======================*/
/* out: space id, ULINT_UNDEFINED if not
found */
char* name) /* in: table name in the standard
'databasename/tablename' format */
{
fil_system_t* system = fil_system;
fil_space_t* namespace;
ulint id = ULINT_UNDEFINED;
char path[OS_FILE_MAX_PATH];
ut_ad(system);
mutex_enter(&(system->mutex));
sprintf(path, "%s/%s.ibd", fil_path_to_mysql_datadir, name);
srv_normalize_path_for_win(path);
/* Look if there is a space with the same name; the name is the
directory path to the file */
HASH_SEARCH(name_hash, system->name_hash,
ut_fold_string(path), namespace,
0 == strcmp(namespace->name, path));
if (namespace) {
id = namespace->id;
}
mutex_exit(&(system->mutex));
return(TRUE);
return(id);
}
/**************************************************************************
Tries to extend a data file by the number of pages given. Fractions of 1 MB
are ignored. The tablespace must be cached in the memory cache. */
Tries to extend a data file so that it would accommodate the number of pages
given. The tablespace must be cached in the memory cache. If the space is big
enough already, does nothing. */
ibool
fil_extend_last_data_file(
/*======================*/
/* out: TRUE if success, also if we run
out of disk space we may return TRUE */
ulint* actual_increase,/* out: number of pages we were able to
extend, here the original size of the file and
the resulting size of the file are rounded
downwards to a full megabyte, and the
difference expressed in pages is returned */
ulint space_id, /* in: space id */
ulint size, /* in: current size of the space in pages, as
stored in the fsp header */
ulint size_increase) /* in: try to extend this many pages */
fil_extend_space_to_desired_size(
/*=============================*/
/* out: TRUE if success */
ulint* actual_size, /* out: size of the space after extension;
if we ran out of disk space this may be lower
than the desired size */
ulint space_id, /* in: space id, must be != 0 */
ulint size_after_extend)/* in: desired size in pages after the
extension; if the current space size is bigger
than this already, the function does nothing */
{
fil_system_t* system = fil_system;
fil_node_t* node;
fil_space_t* space;
byte* buf2;
byte* buf;
ibool success;
ulint i;
ulint start_page_no;
ulint file_start_page_no;
ulint n_pages;
ulint offset_high;
ulint offset_low;
ibool success = TRUE;
fil_mutex_enter_and_prepare_for_io(space_id);
......@@ -2662,138 +3105,149 @@ fil_extend_last_data_file(
space->id == space_id);
ut_a(space);
if (space->size >= size_after_extend) {
/* Space already big enough */
*actual_size = space->size;
mutex_exit(&(system->mutex));
return(TRUE);
}
node = UT_LIST_GET_LAST(space->chain);
fil_node_prepare_for_io(node, system, space);
if (UT_LIST_GET_LEN(space->chain) == 1 && node->size < size) {
ut_print_timestamp(stderr);
fprintf(stderr,
"InnoDB: Fatal error: space %s id %lu size stored in header is %lu pages\n"
"InnoDB: but actual size is only %lu pages (possibly rounded downwards)!\n"
"InnoDB: Cannot continue operation!\n", space->name, space->id, size,
node->size);
exit(1);
}
/* Extend 1 MB at a time */
buf2 = mem_alloc(1024 * 1024 + UNIV_PAGE_SIZE);
buf = ut_align(buf2, UNIV_PAGE_SIZE);
memset(buf, '\0', 1024 * 1024);
for (i = 0; i < size_increase / ((1024 * 1024) / UNIV_PAGE_SIZE);
i++) {
/* If we use native Windows aio, then we use it also in this
write */
start_page_no = space->size;
file_start_page_no = space->size - node->size;
while (start_page_no < size_after_extend) {
n_pages = size_after_extend - start_page_no;
if (n_pages > (1024 * 1024) / UNIV_PAGE_SIZE) {
n_pages = (1024 * 1024) / UNIV_PAGE_SIZE;
}
offset_high = (start_page_no - file_start_page_no)
/ (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE));
offset_low = ((start_page_no - file_start_page_no)
% (4096 * ((1024 * 1024) / UNIV_PAGE_SIZE)))
* UNIV_PAGE_SIZE;
#ifdef UNIV_HOTBACKUP
success = os_file_write(node->name, node->handle, buf,
offset_low, offset_high,
UNIV_PAGE_SIZE * n_pages);
#else
success = os_aio(OS_FILE_WRITE, OS_AIO_SYNC,
node->name, node->handle, buf,
(node->size << UNIV_PAGE_SIZE_SHIFT) & 0xFFFFFFFFUL,
node->size >> (32 - UNIV_PAGE_SIZE_SHIFT),
1024 * 1024, NULL, NULL);
offset_low, offset_high,
UNIV_PAGE_SIZE * n_pages,
NULL, NULL);
#endif
if (success) {
node->size += n_pages;
space->size += n_pages;
os_has_said_disk_full = FALSE;
} else {
/* Let us measure the size of the file to determine
how much we were able to extend it */
n_pages = ((ulint)
(os_file_get_size_as_iblonglong(node->handle)
/ UNIV_PAGE_SIZE)) - node->size;
node->size += n_pages;
space->size += n_pages;
if (!success) {
break;
}
node->size += ((1024 * 1024) / UNIV_PAGE_SIZE);
space->size += ((1024 * 1024) / UNIV_PAGE_SIZE);
os_has_said_disk_full = FALSE;
start_page_no += n_pages;
}
mem_free(buf2);
fil_node_complete_io(node, system, OS_FILE_WRITE);
*actual_size = space->size;
/*
printf("Extended %s to %lu, actual size %lu pages\n", space->name,
size_after_extend, *actual_size); */
mutex_exit(&(system->mutex));
*actual_increase = i * ((1024 * 1024) / UNIV_PAGE_SIZE);
fil_flush(space_id);
if (space_id == 0) {
srv_data_file_sizes[srv_n_data_files - 1] += *actual_increase;
}
return(TRUE);
return(success);
}
/**************************************************************************
Tries to extend a data file so that it would accommodate the number of pages
given. The tablespace must be cached in the memory cache. */
#ifdef UNIV_HOTBACKUP
/************************************************************************
Extends all tablespaces to the size stored in the space header. During the
ibbackup --apply-log phase we extended the spaces on-demand so that log records
could be appllied, but that may have left spaces still too small compared to
the size stored in the space header. */
ibool
fil_extend_data_file_with_pages(
/*============================*/
/* out: TRUE if success */
ulint space_id, /* in: space id, must be != 0 */
ulint size, /* in: current size of the space in pages, as
stored in the fsp header */
ulint size_after_extend)/* in: desired size in pages after the
extension, should be less than 4 GB (this
function is primarily intended for increasing
the data file size from < 64 pages to up to
64 pages) */
void
fil_extend_tablespaces_to_stored_len(void)
/*======================================*/
{
fil_system_t* system = fil_system;
fil_node_t* node;
fil_space_t* space;
byte* buf2;
byte* buf;
ulint actual_size;
ulint size_in_header;
ulint error;
ibool success;
ut_a(space_id != 0);
ut_a(size_after_extend < 64 * 4096);
ut_a(size_after_extend >= size);
buf = mem_alloc(UNIV_PAGE_SIZE);
fil_mutex_enter_and_prepare_for_io(space_id);
mutex_enter(&(system->mutex));
HASH_SEARCH(hash, system->spaces, space_id, space,
space->id == space_id);
ut_a(space);
space = UT_LIST_GET_FIRST(system->space_list);
node = UT_LIST_GET_LAST(space->chain);
while (space) {
ut_a(space->purpose == FIL_TABLESPACE);
fil_node_prepare_for_io(node, system, space);
mutex_exit(&(system->mutex)); /* no need to protect with a
mutex, because this is a single-
threaded operation */
error = fil_read(TRUE, space->id, 0, 0, UNIV_PAGE_SIZE, buf,
NULL);
ut_a(error == DB_SUCCESS);
if (UT_LIST_GET_LEN(space->chain) == 1 && node->size < size) {
ut_print_timestamp(stderr);
size_in_header = fsp_get_size_low(buf);
success = fil_extend_space_to_desired_size(&actual_size,
space->id, size_in_header);
if (!success) {
fprintf(stderr,
"InnoDB: Fatal error: space %s id %lu size stored in header is %lu pages\n"
"InnoDB: but actual size is only %lu pages (possibly rounded downwards)!\n"
"InnoDB: Cannot continue operation!\n", space->name, space_id, size,
node->size);
"InnoDB: Error: could not extend the tablespace of %s\n"
"InnoDB: to the size stored in header, %lu pages;\n"
"InnoDB: size after extension %lu pages\n"
"InnoDB: Check that you have free disk space and retry!\n", space->name,
size_in_header, actual_size);
exit(1);
}
buf2 = mem_alloc((1 + size_after_extend - size) * UNIV_PAGE_SIZE);
buf = ut_align(buf2, UNIV_PAGE_SIZE);
memset(buf, '\0', (size_after_extend - size) * UNIV_PAGE_SIZE);
success = os_aio(OS_FILE_WRITE, OS_AIO_SYNC,
node->name, node->handle, buf,
UNIV_PAGE_SIZE * size, 0,
UNIV_PAGE_SIZE * (size_after_extend - size),
NULL, NULL);
if (success) {
node->size = size_after_extend;
space->size = size_after_extend;
mutex_enter(&(system->mutex));
os_has_said_disk_full = FALSE;
space = UT_LIST_GET_NEXT(space_list, space);
}
mem_free(buf2);
fil_node_complete_io(node, system, OS_FILE_WRITE);
mutex_exit(&(system->mutex));
fil_flush(space_id);
return(success);
mem_free(buf);
}
#endif
/*========== RESERVE FREE EXTENTS (for a B-tree split, for example) ===*/
......@@ -3123,12 +3577,23 @@ fil_io(
/* Do aio */
ut_anp(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_anp((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
ut_a(byte_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a((len % OS_FILE_LOG_BLOCK_SIZE) == 0);
#ifdef UNIV_HOTBACKUP
/* In ibbackup do normal i/o, not aio */
if (type == OS_FILE_READ) {
ret = os_file_read(node->handle, buf, offset_low, offset_high,
len);
} else {
ret = os_file_write(node->name, node->handle, buf,
offset_low, offset_high, len);
}
#else
/* Queue the aio request */
ret = os_aio(type, mode | wake_later, node->name, node->handle, buf,
offset_low, offset_high, len, node, message);
#endif
ut_a(ret);
if (mode == OS_AIO_SYNC) {
......
......@@ -27,6 +27,10 @@ Created 11/29/1995 Heikki Tuuri
#include "dict0mem.h"
#include "log0log.h"
#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
within a file page */
/* The data structures in files are defined just as byte strings in C */
typedef byte fsp_header_t;
typedef byte xdes_t;
......@@ -38,8 +42,6 @@ File space header data structure: this data structure is contained in the
first page of a space. The space for this header is reserved in every extent
descriptor page, but used only in the first. */
#define FSP_HEADER_OFFSET FIL_PAGE_DATA /* Offset of the space header
within a file page */
/*-------------------------------------*/
#define FSP_SPACE_ID 0 /* space id */
#define FSP_NOT_USED 4 /* this field contained a value up to
......@@ -91,7 +93,6 @@ descriptor page, but used only in the first. */
to the free list from above
FSP_FREE_LIMIT at a time */
/* FILE SEGMENT INODE
==================
......@@ -298,6 +299,19 @@ fseg_alloc_free_page_low(
FSP_UP, FSP_NO_DIR */
mtr_t* mtr); /* in: mtr handle */
/**************************************************************************
Reads the file space size stored in the header page. */
ulint
fsp_get_size_low(
/*=============*/
/* out: tablespace size stored in the space header */
page_t* page) /* in: header page (page 0 in the tablespace) */
{
return(mach_read_from_4(page + FSP_HEADER_OFFSET + FSP_SIZE));
}
/**************************************************************************
Gets a pointer to the space header and x-locks its page. */
UNIV_INLINE
......@@ -1034,8 +1048,9 @@ fsp_try_extend_data_file_with_pages(
fsp_header_t* header, /* in: space header */
mtr_t* mtr) /* in: mtr */
{
ulint size;
ibool success;
ulint actual_size;
ulint size;
ut_a(space != 0);
......@@ -1043,12 +1058,12 @@ fsp_try_extend_data_file_with_pages(
ut_a(page_no >= size);
success = fil_extend_data_file_with_pages(space, size, page_no + 1);
success = fil_extend_space_to_desired_size(&actual_size, space,
page_no + 1);
/* actual_size now has the space size in pages; it may be less than
we wanted if we ran out of disk space */
if (success) {
mlog_write_ulint(header + FSP_SIZE, page_no + 1, MLOG_4BYTES,
mtr);
}
mlog_write_ulint(header + FSP_SIZE, actual_size, MLOG_4BYTES, mtr);
return(success);
}
......@@ -1060,13 +1075,20 @@ ibool
fsp_try_extend_data_file(
/*=====================*/
/* out: FALSE if not auto-extending */
ulint* actual_increase,/* out: actual increase in pages */
ulint* actual_increase,/* out: actual increase in pages, where
we measure the tablespace size from
what the header field says; it may be
the actual file size rounded down to
megabyte */
ulint space, /* in: space */
fsp_header_t* header, /* in: space header */
mtr_t* mtr) /* in: mtr */
{
ulint size;
ulint new_size;
ulint old_size;
ulint size_increase;
ulint actual_size;
ibool success;
*actual_increase = 0;
......@@ -1078,6 +1100,8 @@ fsp_try_extend_data_file(
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
old_size = size;
if (space == 0 && srv_last_file_size_max != 0) {
if (srv_last_file_size_max
< srv_data_file_sizes[srv_n_data_files - 1]) {
......@@ -1107,8 +1131,12 @@ fsp_try_extend_data_file(
success = fsp_try_extend_data_file_with_pages(
space, FSP_EXTENT_SIZE - 1,
header, mtr);
if (!success) {
new_size = mtr_read_ulint(
header + FSP_SIZE, MLOG_4BYTES, mtr);
*actual_increase = new_size - old_size;
return(FALSE);
}
......@@ -1118,7 +1146,10 @@ fsp_try_extend_data_file(
if (size < 32 * FSP_EXTENT_SIZE) {
size_increase = FSP_EXTENT_SIZE;
} else {
size_increase = 8 * FSP_EXTENT_SIZE;
/* Below in fsp_fill_free_list() we assume
that we add at most FSP_FREE_ADD extents at
a time */
size_increase = FSP_FREE_ADD * FSP_EXTENT_SIZE;
}
}
}
......@@ -1128,18 +1159,17 @@ fsp_try_extend_data_file(
return(TRUE);
}
/* Extend the data file. If we are not able to extend the full
requested length, the function tells how many pages we were able to
extend so that the size of the tablespace would be divisible by 1 MB
(we possibly managed to extend more, but we only take into account
full megabytes). */
success = fil_extend_space_to_desired_size(&actual_size, space,
size + size_increase);
/* We ignore any fragments of a full megabyte when storing the size
to the space header */
success = fil_extend_last_data_file(actual_increase, space, size,
size_increase);
if (success) {
mlog_write_ulint(header + FSP_SIZE, size + *actual_increase,
mlog_write_ulint(header + FSP_SIZE,
ut_calc_align_down(actual_size, (1024 * 1024) / UNIV_PAGE_SIZE),
MLOG_4BYTES, mtr);
}
new_size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
*actual_increase = new_size - old_size;
return(TRUE);
}
......@@ -1186,8 +1216,10 @@ fsp_fill_free_list(
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
}
if (space != 0 && !init_space) {
/* Try to increase the data file size */
if (space != 0 && !init_space
&& size < limit + FSP_EXTENT_SIZE * FSP_FREE_ADD) {
/* Try to increase the .ibd file size */
fsp_try_extend_data_file(&actual_increase, space, header, mtr);
size = mtr_read_ulint(header + FSP_SIZE, MLOG_4BYTES, mtr);
}
......@@ -1222,7 +1254,7 @@ fsp_fill_free_list(
fsp_init_file_page(descr_page, mtr);
}
/* Initialize the ibuf page in a separate
/* Initialize the ibuf bitmap page in a separate
mini-transaction because it is low in the latching
order, and we must be able to release its latch
before returning from the fsp routine */
......@@ -3157,7 +3189,7 @@ fseg_free_step(
freed yet */
ut_a(descr);
ut_anp(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header)
ut_a(xdes_get_bit(descr, XDES_FREE_BIT, buf_frame_get_page_no(header)
% FSP_EXTENT_SIZE, mtr) == FALSE);
inode = fseg_inode_get(header, mtr);
......
......@@ -16,6 +16,14 @@ Created 10/25/1995 Heikki Tuuri
#include "ut0byte.h"
#include "os0file.h"
/* When mysqld is run, the default directory "." is the mysqld datadir, but in
ibbackup we must set it explicitly; the patgh must NOT contain the trailing
'/' or '\' */
extern char* fil_path_to_mysql_datadir;
/* Initial size of a single-table tablespace in pages */
#define FIL_IBD_FILE_INITIAL_SIZE 4
/* 'null' (undefined) page offset in the context of file spaces */
#define FIL_NULL ULINT32_UNDEFINED
......@@ -261,6 +269,35 @@ fil_decr_pending_ibuf_merges(
/*========================*/
ulint id); /* in: space id */
/***********************************************************************
Parses the body of a log record written about an .ibd file operation. That is,
the log record part after the standard (type, space id, page no) header of the
log record.
If desired, also replays the delete or rename operation if the .ibd file
exists and the space id in it matches. Replays the create operation if a file
at that path does not exist yet. If the database directory for the file to be
created does not exist, then we create the directory, too.
Note that ibbackup --apply-log sets fil_path_to_mysql_datadir to point to the
datadir that we should use in replaying the file operations. */
byte*
fil_op_log_parse_or_replay(
/*=======================*/
/* out: end of log record, or NULL if the
record was not completely contained between
ptr and end_ptr */
byte* ptr, /* in: buffer containing the log record body,
or an initial segment of it, if the record does
not fir completely between ptr and end_ptr */
byte* end_ptr, /* in: buffer end */
ulint type, /* in: the type of this log record */
ibool do_replay, /* in: TRUE if we want to replay the
operation, and not just parse the log record */
ulint space_id); /* in: if do_replay is TRUE, the space id of
the tablespace in question; otherwise
ignored */
/***********************************************************************
Deletes a single-table tablespace. The tablespace must be cached in the
memory cache. */
......@@ -306,16 +343,18 @@ ulint
fil_create_new_single_table_tablespace(
/*===================================*/
/* out: DB_SUCCESS or error code */
ulint* space_id, /* out: space id */
ulint* space_id, /* in/out: space id; if this is != 0, then
this is an input parameter, otherwise
output */
char* tablename, /* in: the table name in the usual
databasename/tablename format of InnoDB */
ulint size); /* in: the initial size of the tablespace file
in pages */
in pages, must be > 0 */
/************************************************************************
Tries to open a single-table tablespace and checks the space id is right in
it. If does not succeed, prints an error message to the .err log. This
function is used to open the tablespace when we load a table definition
to the dictionarky cache. NOTE that we assume this operation is used under the
to the dictionary cache. NOTE that we assume this operation is used under the
protection of the dictionary mutex, so that two users cannot race here. */
ibool
......@@ -410,39 +449,32 @@ fil_space_for_table_exists_in_mem(
the .err log if a matching tablespace is
not found from memory */
/**************************************************************************
Tries to extend a data file by the number of pages given. Fractions of 1 MB
are ignored. The tablespace must be cached in the memory cache. */
ibool
fil_extend_last_data_file(
/*======================*/
/* out: TRUE if success, also if we run
out of disk space we may return TRUE */
ulint* actual_increase,/* out: number of pages we were able to
extend, here the original size of the file and
the resulting size of the file are rounded
downwards to a full megabyte, and the
difference expressed in pages is returned */
ulint space_id, /* in: space id */
ulint size, /* in: current size of the space in pages, as
stored in the fsp header */
ulint size_increase); /* in: try to extend this many pages */
/**************************************************************************
Tries to extend a data file so that it would accommodate the number of pages
given. The tablespace must be cached in the memory cache. */
given. The tablespace must be cached in the memory cache. If the space is big
enough already, does nothing. */
ibool
fil_extend_data_file_with_pages(
/*============================*/
fil_extend_space_to_desired_size(
/*=============================*/
/* out: TRUE if success */
ulint* actual_size, /* out: size of the space after extension;
if we ran out of disk space this may be lower
than the desired size */
ulint space_id, /* in: space id, must be != 0 */
ulint size, /* in: current size of the space in pages, as
stored in the fsp header */
ulint size_after_extend);/* in: desired size in pages after the
extension, should be less than 4 GB (this
function is primarily intended for increasing
the data file size from < 64 pages to up to
64 pages) */
extension; if the current space size is bigger
than this already, the function does nothing */
#ifdef UNIV_HOTBACKUP
/************************************************************************
Extends all tablespaces to the size stored in the space header. During the
ibbackup --apply-log phase we extended the spaces on-demand so that log records
could be appllied, but that may have left spaces still too small compared to
the size stored in the space header. */
void
fil_extend_tablespaces_to_stored_len(void);
/*======================================*/
#endif
/***********************************************************************
Tries to reserve free extents in a file space. */
......
......@@ -67,6 +67,14 @@ fsp_header_get_tablespace_size(
/* out: size in pages */
ulint space); /* in: space id, must be 0 */
/**************************************************************************
Reads the file space size stored in the header page. */
ulint
fsp_get_size_low(
/*=============*/
/* out: tablespace size stored in the space header */
page_t* page); /* in: header page (page 0 in the tablespace) */
/**************************************************************************
Reads the space id from the first page of a tablespace. */
ulint
......
......@@ -51,8 +51,6 @@ ha_chain_get_next(
/* out: next node, NULL if none */
ha_node_t* node) /* in: hash chain node */
{
ut_ad(table);
return(node->next);
}
......@@ -144,8 +142,6 @@ ha_next(
fold = node->fold;
ut_ad(!table->mutexes || mutex_own(hash_get_mutex(table, fold)));
node = ha_chain_get_next(node);
while (node) {
......
......@@ -175,17 +175,14 @@ recv_apply_hashed_log_recs(
disk and invalidated in buffer pool: this
alternative means that no new log records
can be generated during the application */
#ifdef UNIV_HOTBACKUP
/***********************************************************************
Applies log records in the hash table to a backup. */
void
recv_apply_log_recs_for_backup(
/*===========================*/
ulint n_data_files, /* in: number of data files */
char** data_files, /* in: array containing the paths to the
data files */
ulint* file_sizes); /* in: sizes of the data files in database
pages */
recv_apply_log_recs_for_backup(void);
/*================================*/
#endif
/************************************************************
Recovers from archived log files, and also from log files, if they exist. */
......
......@@ -58,6 +58,19 @@ mlog_write_initial_log_record(
byte type, /* in: log item type: MLOG_1BYTE, ... */
mtr_t* mtr); /* in: mini-transaction handle */
/************************************************************
Writes a log record about an .ibd file create/delete/rename. */
UNIV_INLINE
byte*
mlog_write_initial_log_record_for_file_op(
/*======================================*/
/* out: new value of log_ptr */
ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or
MLOG_FILE_RENAME */
ulint space_id,/* in: space id, if applicable */
ulint page_no,/* in: page number (not relevant currently) */
byte* log_ptr,/* in: pointer to mtr log which has been opened */
mtr_t* mtr); /* in: mtr */
/************************************************************
Catenates 1 - 4 bytes to the mtr log. */
UNIV_INLINE
void
......
......@@ -185,3 +185,31 @@ mlog_write_initial_log_record_fast(
#endif
return(log_ptr);
}
/************************************************************
Writes a log record about an .ibd file create/delete/rename. */
UNIV_INLINE
byte*
mlog_write_initial_log_record_for_file_op(
/*======================================*/
/* out: new value of log_ptr */
ulint type, /* in: MLOG_FILE_CREATE, MLOG_FILE_DELETE, or
MLOG_FILE_RENAME */
ulint space_id,/* in: space id, if applicable */
ulint page_no,/* in: page number (not relevant currently) */
byte* log_ptr,/* in: pointer to mtr log which has been opened */
mtr_t* mtr) /* in: mtr */
{
ut_ad(log_ptr);
mach_write_to_1(log_ptr, type);
log_ptr++;
/* We write dummy space id and page number */
log_ptr += mach_write_compressed(log_ptr, space_id);
log_ptr += mach_write_compressed(log_ptr, page_no);
mtr->n_log_recs++;
return(log_ptr);
}
......@@ -96,7 +96,13 @@ flag value must give the length also! */
sequence of these records */
#define MLOG_DUMMY_RECORD ((byte)32) /* dummy log record used to
pad a log block full */
#define MLOG_BIGGEST_TYPE ((byte)32) /* biggest value (used in
#define MLOG_FILE_CREATE ((byte)33) /* log record about an .ibd
file creation */
#define MLOG_FILE_RENAME ((byte)34) /* log record about an .ibd
file rename */
#define MLOG_FILE_DELETE ((byte)35) /* log record about an .ibd
file deletion */
#define MLOG_BIGGEST_TYPE ((byte)35) /* biggest value (used in
asserts) */
/*******************************************************************
......
......@@ -63,6 +63,7 @@ log. */
#define OS_FILE_READ_ONLY 333
#define OS_FILE_READ_WRITE 444
#define OS_FILE_READ_ALLOW_DELETE 555 /* for ibbackup */
/* Options for file_create */
#define OS_FILE_AIO 61
......@@ -199,6 +200,21 @@ os_file_readdir_next_file(
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 */
/*********************************************************************
This function attempts to create a directory named pathname. The new directory
gets default permissions. On Unix, the permissions are (0770 & ~umask). If the
directory exists already, nothing is done and the call succeeds, unless the
fail_if_exists arguments is true. */
ibool
os_file_create_directory(
/*=====================*/
/* out: TRUE if call succeeds, FALSE on
error */
char* pathname, /* in: directory name as null-terminated
string */
ibool fail_if_exists);/* in: if TRUE, pre-existing directory is
treated as an error. */
/********************************************************************
A simple function to open or create a file. */
......@@ -206,7 +222,8 @@ os_file_t
os_file_create_simple(
/*==================*/
/* out, own: handle to the file, not defined if error,
error number can be retrieved with os_get_last_error */
error number can be retrieved with
os_file_get_last_error */
char* name, /* in: name of the file or path as a null-terminated
string */
ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened
......@@ -221,13 +238,16 @@ os_file_t
os_file_create_simple_no_error_handling(
/*====================================*/
/* out, own: handle to the file, not defined if error,
error number can be retrieved with os_get_last_error */
error number can be retrieved with
os_file_get_last_error */
char* name, /* in: name of the file or path as a null-terminated
string */
ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened
(if does not exist, error), or OS_FILE_CREATE if a new
file is created (if exists, error) */
ulint access_type,/* in: OS_FILE_READ_ONLY or OS_FILE_READ_WRITE */
ulint access_type,/* in: OS_FILE_READ_ONLY, OS_FILE_READ_WRITE, or
OS_FILE_READ_ALLOW_DELETE; the last option is used by
a backup program reading the file */
ibool* success);/* out: TRUE if succeed, FALSE if error */
/********************************************************************
Opens an existing file or creates a new. */
......@@ -236,7 +256,8 @@ os_file_t
os_file_create(
/*===========*/
/* out, own: handle to the file, not defined if error,
error number can be retrieved with os_get_last_error */
error number can be retrieved with
os_file_get_last_error */
char* name, /* in: name of the file or path as a null-terminated
string */
ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened
......
......@@ -30,39 +30,8 @@ extern ulint* ut_dbg_null_ptr;
" InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\
os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\
(ulint)__LINE__);\
fprintf(stderr,\
"InnoDB: Failing assertion: " #EXPR);\
fprintf(stderr,\
"\nInnoDB: We intentionally generate a memory trap.\n");\
fprintf(stderr,\
"InnoDB: Send a detailed bug report to mysql@lists.mysql.com\n");\
ut_dbg_stop_threads = TRUE;\
dbg_i = *(ut_dbg_null_ptr);\
if (dbg_i) {\
ut_dbg_null_ptr = NULL;\
}\
}\
if (ut_dbg_stop_threads) {\
fprintf(stderr,\
"InnoDB: Thread %lu stopped in file %s line %lu\n",\
os_thread_pf(os_thread_get_curr_id()), IB__FILE__, (ulint)__LINE__);\
os_thread_sleep(1000000000);\
}\
}
/* This can be used if there are % characters in the assertion formula:
if we try to printf the formula gcc would complain of illegal print
format characters */
#define ut_anp(EXPR)\
{\
ulint dbg_i;\
\
if (!((ulint)(EXPR) + ut_dbg_zero)) {\
ut_print_timestamp(stderr);\
fprintf(stderr,\
" InnoDB: Assertion failure in thread %lu in file %s line %lu\n",\
os_thread_pf(os_thread_get_curr_id()), IB__FILE__,\
(ulint)__LINE__);\
fputs(\
"InnoDB: Failing assertion: " #EXPR, stderr);\
fprintf(stderr,\
"\nInnoDB: We intentionally generate a memory trap.\n");\
fprintf(stderr,\
......
......@@ -139,7 +139,7 @@ void
ut_ulint_sort(ulint* arr, ulint* aux_arr, ulint low, ulint high);
/*============================================================*/
/************************************************************
The following function returns a clock time in milliseconds. */
The following function returns elapsed CPU time in milliseconds. */
ulint
ut_clock(void);
......@@ -174,6 +174,14 @@ ut_sprintf_timestamp(
/*=================*/
char* buf); /* in: buffer where to sprintf */
/**************************************************************
Sprintfs a timestamp to a buffer with no spaces and with ':' characters
replaced by '_'. */
void
ut_sprintf_timestamp_without_extra_chars(
/*=====================================*/
char* buf); /* in: buffer where to sprintf */
/**************************************************************
Returns current year, month, day. */
void
......
......@@ -95,14 +95,6 @@ static
void
log_io_complete_archive(void);
/*=========================*/
/********************************************************************
Tries to establish a big enough margin of free space in the log groups, such
that a new log entry can be catenated without an immediate need for a
archiving. */
static
void
log_archive_margin(void);
/*====================*/
/********************************************************************
Sets the global variable log_fsp_current_free_limit. Also makes a checkpoint,
......@@ -407,7 +399,7 @@ log_pad_current_log_block(void)
log_close();
log_release();
ut_anp((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE)
ut_a((ut_dulint_get_low(lsn) % OS_FILE_LOG_BLOCK_SIZE)
== LOG_BLOCK_HDR_SIZE);
}
......@@ -745,7 +737,8 @@ log_init(void)
memset(log_sys->checkpoint_buf, '\0', OS_FILE_LOG_BLOCK_SIZE);
/*----------------------------*/
log_sys->archiving_state = LOG_ARCH_ON;
/* Under MySQL, log archiving is always off */
log_sys->archiving_state = LOG_ARCH_OFF;
log_sys->archived_lsn = log_sys->lsn;
log_sys->next_archived_lsn = ut_dulint_zero;
......@@ -754,13 +747,15 @@ log_init(void)
rw_lock_create(&(log_sys->archive_lock));
rw_lock_set_level(&(log_sys->archive_lock), SYNC_NO_ORDER_CHECK);
log_sys->archive_buf = ut_align(
log_sys->archive_buf = NULL;
/* ut_align(
ut_malloc(LOG_ARCHIVE_BUF_SIZE
+ OS_FILE_LOG_BLOCK_SIZE),
OS_FILE_LOG_BLOCK_SIZE);
log_sys->archive_buf_size = LOG_ARCHIVE_BUF_SIZE;
OS_FILE_LOG_BLOCK_SIZE); */
log_sys->archive_buf_size = 0;
memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE);
/* memset(log_sys->archive_buf, '\0', LOG_ARCHIVE_BUF_SIZE); */
log_sys->archiving_on = os_event_create(NULL);
......@@ -1107,8 +1102,8 @@ log_group_write_buf(
ulint i;
ut_ad(mutex_own(&(log_sys->mutex)));
ut_anp(len % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_anp(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(len % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
if (new_data_offset == 0) {
write_header = TRUE;
......@@ -2080,6 +2075,8 @@ log_archived_file_name_gen(
ulint id, /* in: group id */
ulint file_no)/* in: file number */
{
ut_a(0);
UT_NOT_USED(id); /* Currently we only archive the first group */
sprintf(buf, "%sib_arch_log_%010lu", srv_arch_dir, file_no);
......@@ -2101,6 +2098,8 @@ log_group_archive_file_header_write(
byte* buf;
ulint dest_offset;
ut_a(0);
ut_ad(mutex_own(&(log_sys->mutex)));
ut_a(nth_file < group->n_files);
......@@ -2138,6 +2137,8 @@ log_group_archive_completed_header_write(
byte* buf;
ulint dest_offset;
ut_a(0);
ut_ad(mutex_own(&(log_sys->mutex)));
ut_a(nth_file < group->n_files);
......@@ -2177,15 +2178,17 @@ log_group_archive(
ulint n_files;
ulint open_mode;
ut_a(0);
ut_ad(mutex_own(&(log_sys->mutex)));
start_lsn = log_sys->archived_lsn;
ut_anp(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(ut_dulint_get_low(start_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
end_lsn = log_sys->next_archived_lsn;
ut_anp(ut_dulint_get_low(end_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(ut_dulint_get_low(end_lsn) % OS_FILE_LOG_BLOCK_SIZE == 0);
buf = log_sys->archive_buf;
......@@ -2289,7 +2292,7 @@ log_group_archive(
group->next_archived_file_no = group->archived_file_no + n_files;
group->next_archived_offset = next_offset % group->file_size;
ut_anp(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
ut_a(group->next_archived_offset % OS_FILE_LOG_BLOCK_SIZE == 0);
}
/*********************************************************
......@@ -2302,6 +2305,8 @@ log_archive_groups(void)
{
log_group_t* group;
ut_a(0);
ut_ad(mutex_own(&(log_sys->mutex)));
group = UT_LIST_GET_FIRST(log_sys->log_groups);
......@@ -2325,6 +2330,8 @@ log_archive_write_complete_groups(void)
dulint end_lsn;
ulint i;
ut_a(0);
ut_ad(mutex_own(&(log_sys->mutex)));
group = UT_LIST_GET_FIRST(log_sys->log_groups);
......@@ -2387,6 +2394,8 @@ void
log_archive_check_completion_low(void)
/*==================================*/
{
ut_a(0);
ut_ad(mutex_own(&(log_sys->mutex)));
if (log_sys->n_pending_archive_ios == 0
......@@ -2423,6 +2432,8 @@ log_io_complete_archive(void)
{
log_group_t* group;
ut_a(0);
mutex_enter(&(log_sys->mutex));
group = UT_LIST_GET_FIRST(log_sys->log_groups);
......@@ -2458,6 +2469,8 @@ log_archive_do(
dulint start_lsn;
dulint limit_lsn;
ut_a(0);
calc_new_limit = TRUE;
loop:
mutex_enter(&(log_sys->mutex));
......@@ -2484,7 +2497,7 @@ log_archive_do(
start_lsn = log_sys->archived_lsn;
if (calc_new_limit) {
ut_anp(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE
ut_a(log_sys->archive_buf_size % OS_FILE_LOG_BLOCK_SIZE
== 0);
limit_lsn = ut_dulint_add(start_lsn,
log_sys->archive_buf_size);
......@@ -2584,6 +2597,8 @@ log_archive_all(void)
return;
}
ut_a(0);
present_lsn = log_sys->lsn;
mutex_exit(&(log_sys->mutex));
......@@ -2621,11 +2636,17 @@ log_archive_close_groups(
ut_ad(mutex_own(&(log_sys->mutex)));
if (log_sys->archiving_state == LOG_ARCH_OFF) {
return;
}
ut_a(0);
group = UT_LIST_GET_FIRST(log_sys->log_groups);
trunc_len = UNIV_PAGE_SIZE
* fil_space_get_size(group->archive_space_id);
if (trunc_len > 0) {
ut_a(trunc_len == group->file_size);
......@@ -2653,9 +2674,8 @@ log_archive_close_groups(
/********************************************************************
Writes the log contents to the archive up to the lsn when this function was
called, and stops the archiving. When archiving is started again, the archived
log file numbers start from 2 higher, so that the archiving will
not write again to the archived log files which exist when this function
returns. */
log file numbers start from 2 higher, so that the archiving will not write
again to the archived log files which exist when this function returns. */
ulint
log_archive_stop(void)
......@@ -2664,6 +2684,8 @@ log_archive_stop(void)
{
ibool success;
ut_a(0);
mutex_enter(&(log_sys->mutex));
if (log_sys->archiving_state != LOG_ARCH_ON) {
......@@ -2726,6 +2748,8 @@ log_archive_start(void)
/*===================*/
/* out: DB_SUCCESS or DB_ERROR */
{
ut_a(0);
mutex_enter(&(log_sys->mutex));
if (log_sys->archiving_state != LOG_ARCH_STOPPED) {
......@@ -2752,6 +2776,7 @@ log_archive_noarchivelog(void)
/*==========================*/
/* out: DB_SUCCESS or DB_ERROR */
{
ut_a(0);
loop:
mutex_enter(&(log_sys->mutex));
......@@ -2784,6 +2809,7 @@ log_archive_archivelog(void)
/*========================*/
/* out: DB_SUCCESS or DB_ERROR */
{
ut_a(0);
mutex_enter(&(log_sys->mutex));
if (log_sys->archiving_state == LOG_ARCH_OFF) {
......@@ -2802,6 +2828,7 @@ log_archive_archivelog(void)
return(DB_ERROR);
}
#ifdef notdefined
/********************************************************************
Tries to establish a big enough margin of free space in the log groups, such
that a new log entry can be catenated without an immediate need for
......@@ -2855,6 +2882,7 @@ log_archive_margin(void)
goto loop;
}
}
#endif
/************************************************************************
Checks that there is enough free space in the log to start a new query step.
......@@ -2871,7 +2899,7 @@ log_check_margins(void)
log_checkpoint_margin();
log_archive_margin();
/* log_archive_margin(); */
mutex_enter(&(log_sys->mutex));
......@@ -3009,7 +3037,7 @@ logs_empty_and_mark_files_at_shutdown(void)
goto loop;
}
log_archive_all();
/* log_archive_all(); */
log_make_checkpoint_at(ut_dulint_max, TRUE);
mutex_enter(&(log_sys->mutex));
......@@ -3027,15 +3055,16 @@ logs_empty_and_mark_files_at_shutdown(void)
goto loop;
}
arch_log_no =
arch_log_no = 0;
/*
UT_LIST_GET_FIRST(log_sys->log_groups)->archived_file_no;
if (0 == UT_LIST_GET_FIRST(log_sys->log_groups)->archived_offset) {
arch_log_no--;
}
log_archive_close_groups(TRUE);
*/
/* log_archive_close_groups(TRUE); */
mutex_exit(&(log_sys->mutex));
......
......@@ -721,7 +721,7 @@ recv_scan_log_seg_for_backup(
/***********************************************************************
Tries to parse a single log record body and also applies it to a page if
specified. */
specified. File ops are parsed, but not applied in this function. */
static
byte*
recv_parse_or_apply_log_rec_body(
......@@ -798,8 +798,14 @@ recv_parse_or_apply_log_rec_body(
} else if (type == MLOG_INIT_FILE_PAGE) {
new_ptr = fsp_parse_init_file_page(ptr, end_ptr, page);
} else if (type <= MLOG_WRITE_STRING) {
} else if (type == MLOG_WRITE_STRING) {
new_ptr = mlog_parse_string(ptr, end_ptr, page);
} else if (type == MLOG_FILE_CREATE
|| type == MLOG_FILE_RENAME
|| type == MLOG_FILE_DELETE) {
new_ptr = fil_op_log_parse_or_replay(ptr, end_ptr, type, FALSE,
ULINT_UNDEFINED);
} else {
new_ptr = NULL;
......@@ -1322,7 +1328,6 @@ recv_apply_hashed_log_recs(
fprintf(stderr, "%lu ",
(i * 100) / hash_get_n_cells(recv_sys->addr_hash));
}
}
......@@ -1376,130 +1381,132 @@ recv_apply_hashed_log_recs(
}
#ifdef UNIV_HOTBACKUP
/* This page is allocated from the buffer pool and used in the function
below */
page_t* recv_backup_application_page = NULL;
/***********************************************************************
Applies log records in the hash table to a backup. */
void
recv_apply_log_recs_for_backup(
/*===========================*/
ulint n_data_files, /* in: number of data files */
char** data_files, /* in: array containing the paths to the
data files */
ulint* file_sizes) /* in: sizes of the data files in database
pages */
recv_apply_log_recs_for_backup(void)
/*================================*/
{
recv_addr_t* recv_addr;
os_file_t data_file;
ulint n_pages_total = 0;
ulint nth_file = 0;
ulint nth_page_in_file= 0;
ulint n_hash_cells;
byte* page;
ulint actual_size;
ibool success;
ulint error;
ulint i;
recv_sys->apply_log_recs = TRUE;
recv_sys->apply_batch_on = TRUE;
page = buf_pool->frame_zero;
for (i = 0; i < n_data_files; i++) {
n_pages_total += file_sizes[i];
if (recv_backup_application_page == NULL) {
recv_backup_application_page = buf_frame_alloc();
}
if (recv_max_parsed_page_no >= n_pages_total) {
printf(
"InnoDB: Error: tablespace size %lu pages, but a log record on page %lu!\n"
"InnoDB: Are you sure you have specified all the ibdata files right in\n"
"InnoDB: the my.cnf file you gave as the argument to ibbackup --restore?\n",
n_pages_total, recv_max_parsed_page_no);
}
page = recv_backup_application_page;
printf(
"InnoDB: Starting an apply batch of log records to the database...\n"
"InnoDB: Progress in percents: ");
for (i = 0; i < n_pages_total; i++) {
n_hash_cells = hash_get_n_cells(recv_sys->addr_hash);
for (i = 0; i < n_hash_cells; i++) {
/* The address hash table is externally chained */
recv_addr = hash_get_nth_cell(recv_sys->addr_hash, i)->node;
while (recv_addr != NULL) {
if (!fil_tablespace_exists_in_mem(recv_addr->space)) {
/*
printf(
"InnoDB: Warning: cannot apply log record to tablespace %lu page %lu,\n"
"InnoDB: because tablespace with that id does not exist.\n",
recv_addr->space, recv_addr->page_no);
*/
recv_addr->state = RECV_PROCESSED;
ut_a(recv_sys->n_addrs);
recv_sys->n_addrs--;
if (i == 0 || nth_page_in_file == file_sizes[nth_file]) {
if (i != 0) {
nth_file++;
nth_page_in_file = 0;
os_file_flush(data_file);
os_file_close(data_file);
goto skip_this_recv_addr;
}
data_file = os_file_create_simple(data_files[nth_file],
OS_FILE_OPEN,
OS_FILE_READ_WRITE,
&success);
/* We simulate a page read made by the buffer pool, to
make sure the recovery apparatus works ok, for
example, the buf_frame_align() function. We must init
the block corresponding to buf_pool->frame_zero
(== page). */
buf_page_init_for_backup_restore(recv_addr->space,
recv_addr->page_no,
buf_block_align(page));
/* Extend the tablespace's last file if the page_no
does not fall inside its bounds; we assume the last
file is auto-extending, and ibbackup copied the file
when it still was smaller */
success = fil_extend_space_to_desired_size(
&actual_size,
recv_addr->space,
recv_addr->page_no + 1);
if (!success) {
printf(
"InnoDB: Error: cannot open %lu'th data file\n", nth_file);
"InnoDB: Fatal error: cannot extend tablespace %lu to hold %lu pages\n",
recv_addr->space, recv_addr->page_no);
exit(1);
}
}
recv_addr = recv_get_fil_addr_struct(0, i);
/* Read the page from the tablespace file using the
fil0fil.c routines */
if (recv_addr != NULL) {
success = os_file_read(data_file, page,
(nth_page_in_file << UNIV_PAGE_SIZE_SHIFT)
& 0xFFFFFFFFUL,
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE);
if (!success) {
error = fil_io(OS_FILE_READ, TRUE, recv_addr->space,
recv_addr->page_no, 0, UNIV_PAGE_SIZE,
page, NULL);
if (error != DB_SUCCESS) {
printf(
"InnoDB: Error: cannot read page no %lu from %lu'th data file\n",
nth_page_in_file, nth_file);
"InnoDB: Fatal error: cannot read from tablespace %lu page number %lu\n",
recv_addr->space, recv_addr->page_no);
exit(1);
}
/* We simulate a page read made by the buffer pool,
to make sure recovery works ok. We must init the
block corresponding to buf_pool->frame_zero
(== page) */
buf_page_init_for_backup_restore(0, i,
buf_block_align(page));
/* Apply the log records to this page */
recv_recover_page(TRUE, FALSE, page, recv_addr->space,
recv_addr->page_no);
recv_recover_page(TRUE, FALSE, page, 0, i);
/* Write the page back to the tablespace file using the
fil0fil.c routines */
buf_flush_init_for_writing(page,
mach_read_from_8(page + FIL_PAGE_LSN),
0, i);
success = os_file_write(data_files[nth_file],
data_file, page,
(nth_page_in_file << UNIV_PAGE_SIZE_SHIFT)
& 0xFFFFFFFF,
nth_page_in_file >> (32 - UNIV_PAGE_SIZE_SHIFT),
UNIV_PAGE_SIZE);
if (!success) {
printf(
"InnoDB: Error: cannot write page no %lu to %lu'th data file\n",
nth_page_in_file, nth_file);
recv_addr->space, recv_addr->page_no);
exit(1);
}
error = fil_io(OS_FILE_WRITE, TRUE, recv_addr->space,
recv_addr->page_no, 0, UNIV_PAGE_SIZE,
page, NULL);
skip_this_recv_addr:
recv_addr = HASH_GET_NEXT(addr_hash, recv_addr);
}
if ((100 * i) / n_pages_total
!= (100 * (i + 1)) / n_pages_total) {
printf("%lu ", (100 * i) / n_pages_total);
if ((100 * i) / n_hash_cells
!= (100 * (i + 1)) / n_hash_cells) {
printf("%lu ", (100 * i) / n_hash_cells);
fflush(stdout);
}
nth_page_in_file++;
}
os_file_flush(data_file);
os_file_close(data_file);
recv_sys_empty_hash();
}
#endif
#ifdef notdefined
/***********************************************************************
In the debug version, updates the replica of a file page, based on a log
record. */
......@@ -1737,7 +1744,7 @@ recv_parse_log_rec(
return(0);
}
/* Check that space id and page_no are sensible */
/* Check that page_no is sensible */
if (*page_no > 0x8FFFFFFFUL) {
......@@ -1911,12 +1918,16 @@ recv_parse_log_recs(
single_rec = (ulint)*ptr & MLOG_SINGLE_REC_FLAG;
if (single_rec || *ptr == MLOG_DUMMY_RECORD) {
/* The mtr only modified a single page */
/* The mtr only modified a single page, or this is a file op */
old_lsn = recv_sys->recovered_lsn;
/* Try to parse a log record, fetching its type, space id,
page no, and a pointer to the body of the log record */
len = recv_parse_log_rec(ptr, end_ptr, &type, &space,
&page_no, &body);
if (len == 0 || recv_sys->found_corrupt_log) {
if (recv_sys->found_corrupt_log) {
......@@ -1954,6 +1965,26 @@ recv_parse_log_recs(
if (type == MLOG_DUMMY_RECORD) {
/* Do nothing */
} else if (store_to_hash && (type == MLOG_FILE_CREATE
|| type == MLOG_FILE_RENAME
|| type == MLOG_FILE_DELETE)) {
#ifdef UNIV_HOTBACKUP
/* In ibbackup --apply-log, replay an .ibd file
operation, if possible; note that
fil_path_to_mysql_datadir is set in ibbackup to
point to the datadir we should use there */
if (NULL == fil_op_log_parse_or_replay(body, end_ptr,
type, TRUE, space)) {
fprintf(stderr,
"InnoDB: Error: file op log record of type %lu space %lu not complete in\n"
"InnoDB: the replay phase. Path %s\n", (ulint)type, space, (char*)(body + 2));
ut_a(0);
}
#endif
/* In normal mysqld crash recovery we do not try to
replay file operations */
} else if (store_to_hash) {
recv_add_to_hash_table(type, space, page_no, body,
ptr + len, old_lsn,
......@@ -2915,6 +2946,8 @@ recv_reset_log_files_for_backup(
buf = ut_malloc(LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE);
memset(buf, LOG_FILE_HDR_SIZE + OS_FILE_LOG_BLOCK_SIZE, '\0');
for (i = 0; i < n_log_files; i++) {
sprintf(name, "%sib_logfile%lu", log_dir, i);
......@@ -2954,7 +2987,7 @@ recv_reset_log_files_for_backup(
log_block_init_in_old_format(buf + LOG_FILE_HDR_SIZE, lsn);
log_block_set_first_rec_group(buf + LOG_FILE_HDR_SIZE,
LOG_BLOCK_HDR_SIZE);
sprintf(name, "%sib_logfile%lu", log_dir, 0);
sprintf(name, "%sib_logfile%lu", log_dir, 0UL);
log_file = os_file_create_simple(name, OS_FILE_OPEN,
OS_FILE_READ_WRITE, &success);
......@@ -2996,6 +3029,8 @@ log_group_recover_from_archive_file(
int input_char;
char name[10000];
ut_a(0);
try_open_again:
buf = log_sys->buf;
......@@ -3173,6 +3208,8 @@ recv_recovery_from_archive_start(
ibool ret;
ulint err;
ut_a(0);
recv_sys_create();
recv_sys_init(FALSE, buf_pool_get_curr_size());
......@@ -3271,6 +3308,8 @@ void
recv_recovery_from_archive_finish(void)
/*===================================*/
{
ut_a(0);
recv_recovery_from_checkpoint_finish();
recv_recovery_from_backup_on = FALSE;
......
......@@ -603,7 +603,7 @@ mem_pool_validate(
}
}
ut_anp(free + pool->reserved == pool->size);
ut_a(free + pool->reserved == pool->size);
mutex_exit(&(pool->mutex));
......
......@@ -595,6 +595,51 @@ dbname.sym can redirect a database directory:
#endif
}
/*********************************************************************
This function attempts to create a directory named pathname. The new directory
gets default permissions. On Unix the permissions are (0770 & ~umask). If the
directory exists already, nothing is done and the call succeeds, unless the
fail_if_exists arguments is true. */
ibool
os_file_create_directory(
/*=====================*/
/* out: TRUE if call succeeds, FALSE on
error */
char* pathname, /* in: directory name as null-terminated
string */
ibool fail_if_exists) /* in: if TRUE, pre-existing directory is
treated as an error. */
{
#ifdef __WIN__
BOOL rcode;
rcode = CreateDirectory(pathname, NULL);
if (!(rcode != 0 ||
(GetLastError() == ERROR_FILE_EXISTS && !fail_if_exists))) {
/* failure */
os_file_handle_error(NULL, pathname, "CreateDirectory");
return(FALSE);
}
return (TRUE);
#else
int rcode;
rcode = mkdir(pathname, 0770);
if (!(rcode == 0 || (errno == EEXIST && !fail_if_exists))) {
/* failure */
os_file_handle_error(0, pathname, "mkdir");
return(FALSE);
}
return (TRUE);
#endif
}
/********************************************************************
A simple function to open or create a file. */
......@@ -602,7 +647,8 @@ os_file_t
os_file_create_simple(
/*==================*/
/* out, own: handle to the file, not defined if error,
error number can be retrieved with os_get_last_error */
error number can be retrieved with
os_file_get_last_error */
char* name, /* in: name of the file or path as a null-terminated
string */
ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened
......@@ -714,13 +760,16 @@ os_file_t
os_file_create_simple_no_error_handling(
/*====================================*/
/* out, own: handle to the file, not defined if error,
error number can be retrieved with os_get_last_error */
error number can be retrieved with
os_file_get_last_error */
char* name, /* in: name of the file or path as a null-terminated
string */
ulint create_mode,/* in: OS_FILE_OPEN if an existing file is opened
(if does not exist, error), or OS_FILE_CREATE if a new
file is created (if exists, error) */
ulint access_type,/* in: OS_FILE_READ_ONLY or OS_FILE_READ_WRITE */
ulint access_type,/* in: OS_FILE_READ_ONLY, OS_FILE_READ_WRITE, or
OS_FILE_READ_ALLOW_DELETE; the last option is used by
a backup program reading the file */
ibool* success)/* out: TRUE if succeed, FALSE if error */
{
#ifdef __WIN__
......@@ -728,6 +777,7 @@ os_file_create_simple_no_error_handling(
DWORD create_flag;
DWORD access;
DWORD attributes = 0;
DWORD share_mode = FILE_SHARE_READ;
ut_a(name);
......@@ -744,6 +794,13 @@ os_file_create_simple_no_error_handling(
access = GENERIC_READ;
} else if (access_type == OS_FILE_READ_WRITE) {
access = GENERIC_READ | GENERIC_WRITE;
} else if (access_type == OS_FILE_READ_ALLOW_DELETE) {
access = GENERIC_READ;
share_mode = FILE_SHARE_DELETE | FILE_SHARE_READ
| FILE_SHARE_WRITE; /* A backup program has to give
mysqld the maximum freedom to
do what it likes with the
file */
} else {
access = 0;
ut_error;
......@@ -751,8 +808,7 @@ os_file_create_simple_no_error_handling(
file = CreateFile(name,
access,
FILE_SHARE_READ,/* file can be read also by other
processes */
share_mode,
NULL, /* default security attributes */
create_flag,
attributes,
......@@ -808,7 +864,8 @@ os_file_t
os_file_create(
/*===========*/
/* out, own: handle to the file, not defined if error,
error number can be retrieved with os_get_last_error */
error number can be retrieved with
os_file_get_last_error */
char* name, /* in: name of the file or path as a null-terminated
string */
ulint create_mode, /* in: OS_FILE_OPEN if an existing file is opened
......@@ -896,7 +953,7 @@ os_file_create(
start 2 instances of mysqld on the
SAME files, that could cause severe
database corruption! When opening
raw disk partitions Microsoft manuals
raw disk partitions, Microsoft manuals
say that we must give also the write
permission. */
NULL, /* default security attributes */
......@@ -1017,6 +1074,10 @@ os_file_delete(
{
#ifdef __WIN__
BOOL ret;
ulint count = 0;
loop:
/* In Windows, deleting an .ibd file may fail if ibbackup is copying
it */
ret = DeleteFile((LPCTSTR)name);
......@@ -1024,9 +1085,31 @@ os_file_delete(
return(TRUE);
}
os_file_handle_error(NULL, name, "delete");
if (GetLastError() == ERROR_PATH_NOT_FOUND) {
/* If the file does not exist, we classify this as a 'mild'
error and return */
return(FALSE);
}
count++;
if (count > 100 && 0 == (count % 10)) {
fprintf(stderr,
"InnoDB: Warning: cannot delete file %s\n"
"InnoDB: Are you running ibbackup to back up the file?\n", name);
os_file_get_last_error(TRUE); /* print error information */
}
os_thread_sleep(1000000); /* sleep for a second */
if (count > 2000) {
return(FALSE);
}
goto loop;
#else
int ret;
......@@ -1103,6 +1186,7 @@ os_file_close(
}
os_file_handle_error(file, NULL, "close");
return(FALSE);
#else
int ret;
......@@ -1111,6 +1195,7 @@ os_file_close(
if (ret == -1) {
os_file_handle_error(file, NULL, "close");
return(FALSE);
}
......
/* A lexical scanner generated by flex */
/* Scanner skeleton version:
* $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $
* $Header: /home/heikki/cvsroot/ib/pars/lexyy.c,v 1.2 2003/10/30 20:27:19 heikki Exp $
*/
#define FLEX_SCANNER
......
......@@ -2346,8 +2346,13 @@ row_drop_table_for_mysql(
/* Do not drop possible .ibd tablespace if something went
wrong: we do not want to delete valuable data of the user */
if (err == DB_SUCCESS && space_id != 0
&& fil_tablespace_exists_in_mem(space_id)) {
if (err == DB_SUCCESS && space_id > 0) {
if (!fil_space_for_table_exists_in_mem(space_id, name,
FALSE, TRUE)) {
err = DB_ERROR;
goto funct_exit;
}
success = fil_delete_tablespace(space_id);
......
......@@ -3288,7 +3288,13 @@ row_search_for_mysql(
} else if (index == clust_index) {
if (!lock_clust_rec_cons_read_sees(rec, index,
/* Fetch a previous version of the row if the current
one is not visible in the snapshot; if we have a very
high force recovery level set, we try to avoid crashes
by skipping this lookup */
if (srv_force_recovery < 5
&& !lock_clust_rec_cons_read_sees(rec, index,
trx->read_view)) {
err = row_sel_build_prev_vers_for_mysql(
......
......@@ -102,7 +102,7 @@ char** srv_log_group_home_dirs = NULL;
ulint srv_n_log_groups = ULINT_MAX;
ulint srv_n_log_files = ULINT_MAX;
ulint srv_log_file_size = ULINT_MAX; /* size in database pages */
ibool srv_log_archive_on = TRUE;
ibool srv_log_archive_on = FALSE;
ulint srv_log_buffer_size = ULINT_MAX; /* size in database pages */
ulint srv_flush_log_at_trx_commit = 1;
......@@ -3209,11 +3209,13 @@ srv_master_thread(
goto loop;
}
mutex_exit(&kernel_mutex);
/*
srv_main_thread_op_info =
(char*)"archiving log (if log archive is on)";
log_archive_do(FALSE, &n_bytes_archived);
*/
n_bytes_archived = 0;
/* Keep looping in the background loop if still work to do */
......
......@@ -553,7 +553,6 @@ open_or_create_log_file(
ulint i) /* in: log file number in group */
{
ibool ret;
ulint arch_space_id;
ulint size;
ulint size_high;
char name[10000];
......@@ -649,9 +648,10 @@ open_or_create_log_file(
fil_node_create(name, srv_log_file_size,
2 * k + SRV_LOG_SPACE_FIRST_ID, FALSE);
#ifdef notdefined
/* If this is the first log group, create the file space object
for archived logs */
for archived logs.
Under MySQL, no archiving ever done. */
if (k == 0 && i == 0) {
arch_space_id = 2 * k + 1 + SRV_LOG_SPACE_FIRST_ID;
......@@ -661,12 +661,13 @@ open_or_create_log_file(
} else {
arch_space_id = ULINT_UNDEFINED;
}
#endif
if (i == 0) {
log_group_init(k, srv_n_log_files,
srv_log_file_size * UNIV_PAGE_SIZE,
2 * k + SRV_LOG_SPACE_FIRST_ID,
arch_space_id);
SRV_LOG_SPACE_FIRST_ID + 1); /* dummy arch
space id */
}
return(DB_SUCCESS);
......@@ -1000,7 +1001,6 @@ innobase_start_or_create_for_mysql(void)
dulint max_flushed_lsn;
ulint min_arch_log_no;
ulint max_arch_log_no;
ibool start_archive;
ulint sum_of_new_sizes;
ulint sum_of_data_file_sizes;
ulint tablespace_size_in_header;
......@@ -1341,7 +1341,9 @@ NetWare. */
mutex_enter(&(log_sys->mutex));
recv_reset_logs(max_flushed_lsn, max_arch_log_no + 1, TRUE);
/* Do not + 1 arch_log_no because we do not use log
archiving */
recv_reset_logs(max_flushed_lsn, max_arch_log_no, TRUE);
mutex_exit(&(log_sys->mutex));
}
......@@ -1430,6 +1432,8 @@ NetWare. */
log_make_checkpoint_at(ut_dulint_max, TRUE);
#ifdef notdefined
/* Archiving is always off under MySQL */
if (!srv_log_archive_on) {
ut_a(DB_SUCCESS == log_archive_noarchivelog());
} else {
......@@ -1447,7 +1451,7 @@ NetWare. */
ut_a(DB_SUCCESS == log_archive_archivelog());
}
}
#endif
if (!create_new_db && srv_force_recovery == 0) {
/* After a crash recovery we only check that the info in data
dictionary is consistent with what we already know about space
......
......@@ -71,9 +71,8 @@ ut_find_prime(
/* Found a prime */
break;
next_n: ;
next_n: ;
}
return(n);
}
......@@ -63,7 +63,7 @@ ut_get_high32(
}
/************************************************************
The following function returns a clock time in milliseconds. */
The following function returns elapsed CPU time in milliseconds. */
ulint
ut_clock(void)
......@@ -181,6 +181,50 @@ ut_sprintf_timestamp(
#endif
}
/**************************************************************
Sprintfs a timestamp to a buffer with no spaces and with ':' characters
replaced by '_'. */
void
ut_sprintf_timestamp_without_extra_chars(
/*=====================================*/
char* buf) /* in: buffer where to sprintf */
{
#ifdef __WIN__
SYSTEMTIME cal_tm;
GetLocalTime(&cal_tm);
sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
(int)cal_tm.wYear % 100,
(int)cal_tm.wMonth,
(int)cal_tm.wDay,
(int)cal_tm.wHour,
(int)cal_tm.wMinute,
(int)cal_tm.wSecond);
#else
struct tm cal_tm;
struct tm* cal_tm_ptr;
time_t tm;
time(&tm);
#ifdef HAVE_LOCALTIME_R
localtime_r(&tm, &cal_tm);
cal_tm_ptr = &cal_tm;
#else
cal_tm_ptr = localtime(&tm);
#endif
sprintf(buf, "%02d%02d%02d_%2d_%02d_%02d",
cal_tm_ptr->tm_year % 100,
cal_tm_ptr->tm_mon + 1,
cal_tm_ptr->tm_mday,
cal_tm_ptr->tm_hour,
cal_tm_ptr->tm_min,
cal_tm_ptr->tm_sec);
#endif
}
/**************************************************************
Returns current year, month, day. */
......
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