summaryrefslogtreecommitdiff
path: root/innobase/fil
diff options
context:
space:
mode:
authorunknown <heikki@hundin.mysql.fi>2003-11-03 19:11:09 +0200
committerunknown <heikki@hundin.mysql.fi>2003-11-03 19:11:09 +0200
commit8b648b03366a0037b178d5c17a728eda9cccb0e3 (patch)
tree16d8e94df9055bb6ed7e41eb7afbcdebf5b61236 /innobase/fil
parent35564d9fbb1a873247f7d85ecfdd7f475139764c (diff)
downloadmariadb-git-8b648b03366a0037b178d5c17a728eda9cccb0e3.tar.gz
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
Diffstat (limited to 'innobase/fil')
-rw-r--r--innobase/fil/fil0fil.c793
1 files changed, 629 insertions, 164 deletions
diff --git a/innobase/fil/fil0fil.c b/innobase/fil/fil0fil.c
index 3b729938ea7..7bfe7277afa 100644
--- a/innobase/fil/fil0fil.c
+++ b/innobase/fil/fil0fil.c
@@ -23,7 +23,10 @@ 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) {
+ 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);
-
- os_file_get_size(node->handle, &size_low, &size_high);
-
- size_bytes = (((ib_longlong)size_high) << 32)
- + (ib_longlong)size_low;
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 @@ close_more:
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 @@ try_again:
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 @@ try_again:
}
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 @@ try_again:
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 @@ try_again:
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 @@ retry:
/* 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 @@ retry:
/* 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 @@ retry:
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 @@ retry:
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);
}
- *space_id = fil_assign_new_space_id();
+ 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);
+ ut_a(strlen(dbname) + strlen(filename)
+ + strlen(fil_path_to_mysql_datadir) < OS_FILE_MAX_PATH - 100);
- sprintf(filepath, "./%s/%s", dbname, filename);
-
+ 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);
- success = os_file_read(file, page, 0, 0, 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 */
+ /* We have to read the tablespace id from the file */
- space_id = fsp_header_get_space_id(page);
+ 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 @@ next_file_item:
}
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,16 +2956,19 @@ 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) {
- if (mark_space) {
- space->mark = TRUE;
- }
+ if (space && space == namespace) {
+ /* Found */
+
+ if (mark_space) {
+ space->mark = TRUE;
+ }
- mutex_exit(&(system->mutex));
+ mutex_exit(&(system->mutex));
- return(TRUE);
- }
+ return(TRUE);
+ }
+
+ if (!print_error_if_does_not_exist) {
mutex_exit(&(system->mutex));
@@ -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,182 +3026,228 @@ 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);
HASH_SEARCH(hash, system->spaces, space_id, space,
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_system_t* system = fil_system;
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);
-
- node = UT_LIST_GET_LAST(space->chain);
+ space = UT_LIST_GET_FIRST(system->space_list);
- fil_node_prepare_for_io(node, system, space);
+ while (space) {
+ ut_a(space->purpose == FIL_TABLESPACE);
- 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);
- }
+ 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);
- buf2 = mem_alloc((1 + size_after_extend - size) * UNIV_PAGE_SIZE);
- buf = ut_align(buf2, UNIV_PAGE_SIZE);
+ size_in_header = fsp_get_size_low(buf);
- memset(buf, '\0', (size_after_extend - size) * UNIV_PAGE_SIZE);
+ success = fil_extend_space_to_desired_size(&actual_size,
+ space->id, size_in_header);
+ if (!success) {
+ fprintf(stderr,
+"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);
+ }
- 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);
+ mutex_exit(&(system->mutex));
- 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) {