Commit 708eebea authored by unknown's avatar unknown
Browse files

Many files:

  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1


innobase/buf/buf0rea.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/include/dict0load.h:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/include/fil0fil.h:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/include/row0mysql.h:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/include/trx0trx.h:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/dict/dict0load.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/fil/fil0fil.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/row/row0ins.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/row/row0mysql.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/row/row0sel.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/srv/srv0start.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
innobase/trx/trx0trx.c:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
sql/ha_innodb.cc:
  Fix InnoDB critical bug #7496; we scan the InnoDB data dictionary also at a normal mysqld startup, and create the spaces, so that we know the mapping space id -> .ibd file name; fix an infinite loop if DISCARD TABLESPACE coincides with INSERT or some other table operation; fix a potential crash if DISCARD TABLESPACE coincides with a cascaded FOREIGN KEY operation in the same table; do not allow DISCARD TABLESPACE of a referenced table if FOREIGN_KEY_CHECKS=1
parent f2a9080c
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -326,7 +326,7 @@ buf_read_page(
	if (err == DB_TABLESPACE_DELETED) {
	        ut_print_timestamp(stderr);
		fprintf(stderr,
"  InnoDB: error: trying to access tablespace %lu page no. %lu,\n"
"  InnoDB: Error: trying to access tablespace %lu page no. %lu,\n"
"InnoDB: but the tablespace does not exist or is just being dropped.\n",
				 (ulong) space, (ulong) offset);
	}
+25 −5
Original line number Diff line number Diff line
@@ -205,12 +205,14 @@ dict_print(void)
In a crash recovery we already have all the tablespace objects created.
This function compares the space id information in the InnoDB data dictionary
to what we already read with fil_load_single_table_tablespaces().
In a normal startup we just scan the biggest space id, and store it to
fil_system. */

In a normal startup, we create the tablespace objects for every table in
InnoDB's data dictionary, if the corresponding .ibd file exists.
We also scan the biggest space id, and store it to fil_system. */

void
dict_check_tablespaces_or_store_max_id(
/*===================================*/
dict_check_tablespaces_and_store_max_id(
/*====================================*/
	ibool	in_crash_recovery)	/* in: are we doing a crash recovery */
{
	dict_table_t*	sys_tables;
@@ -280,6 +282,14 @@ dict_check_tablespaces_or_store_max_id(
							FALSE, TRUE, TRUE);
		}

		if (space_id != 0 && !in_crash_recovery) {
			/* It is a normal database startup: create the space
			object and check that the .ibd file exists. */

			fil_open_single_table_tablespace(FALSE, space_id,
									name);
		}

		mem_free(name);

		if (space_id > max_space_id) {
@@ -796,8 +806,18 @@ dict_load_table(
			/* Ok; (if we did a crash recovery then the tablespace
			can already be in the memory cache) */
		} else {
			/* In >= 4.1.9, InnoDB scans the data dictionary also
			at a normal mysqld startup. It is an error if the
			space object does not exist in memory. */

			ut_print_timestamp(stderr);
			fprintf(stderr,
"  InnoDB: error: space object of table %s,\n"
"InnoDB: space id %lu did not exist in memory. Retrying an open.\n",
							name, (ulong)space);
			/* Try to open the tablespace */
			if (!fil_open_single_table_tablespace(space, name)) {
			if (!fil_open_single_table_tablespace(TRUE,
							space, name)) {
				/* We failed to find a sensible tablespace
				file */

+78 −15
Original line number Diff line number Diff line
@@ -466,6 +466,10 @@ fil_node_open_file(
	ulint		size_low;
	ulint		size_high;
	ibool		ret;
	byte*		buf2;
	byte*		page;
	ibool		success;
	ulint		space_id;

#ifdef UNIV_SYNC_DEBUG
	ut_ad(mutex_own(&(system->mutex)));
@@ -494,6 +498,8 @@ fil_node_open_file(
	system->n_open++;

	if (node->size == 0) {
		ut_a(space->purpose != FIL_LOG);

		os_file_get_size(node->handle, &size_low, &size_high);

		size_bytes = (((ib_longlong)size_high) << 32)
@@ -507,6 +513,46 @@ fil_node_open_file(

		ut_a(space->id != 0);

		if (size_bytes < 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!", node->name,
			(ulong) size_high,
			(ulong) size_low, (ulong) (4 * UNIV_PAGE_SIZE));
			
			ut_a(0);
		}

		/* Read the first page of the tablespace */

		buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
		/* Align the memory for file i/o if we might have O_DIRECT
		set */
		page = ut_align(buf2, UNIV_PAGE_SIZE);

		success = os_file_read(node->handle, page, 0, 0,
							UNIV_PAGE_SIZE);
		space_id = fsp_header_get_space_id(page);

		ut_free(buf2);
		
		if (space_id == ULINT_UNDEFINED || space_id == 0) {
	        	fprintf(stderr,
"InnoDB: Error: tablespace id %lu in file %s is not sensible\n",
			(ulong) space_id,
			node->name);
			
			ut_a(0);			
		}

		if (space_id != space->id) {
	        	fprintf(stderr,
"InnoDB: Error: tablespace id is %lu in the data dictionary\n"
"InnoDB: but in file %s it is %lu!\n", space->id, node->name, space_id);

			ut_a(0);
		}

		if (size_bytes >= FSP_EXTENT_SIZE * UNIV_PAGE_SIZE) {
			node->size = (ulint) ((size_bytes / (1024 * 1024))
					   * ((1024 * 1024) / UNIV_PAGE_SIZE));
@@ -2487,18 +2533,26 @@ fil_reset_too_high_lsns(
}

/************************************************************************
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 dictionary cache. NOTE that we assume this operation is used under the
protection of the dictionary mutex, so that two users cannot race here. This
operation does not leave the file associated with the tablespace open, but
closes it after we have looked at the space id in it. */
Tries to open a single-table tablespace and optionally 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 a tablespace when we start up mysqld, and also in
IMPORT TABLESPACE.
NOTE that we assume this operation is used either at the database startup
or under the protection of the dictionary mutex, so that two users cannot
race here. This operation does not leave the file associated with the
tablespace open, but closes it after we have looked at the space id in it. */

ibool
fil_open_single_table_tablespace(
/*=============================*/
					/* out: TRUE if success */
	ibool		check_space_id,	/* in: should we check that the space
					id in the file is right; we assume
					that this function runs much faster
					if no check is made, since accessing
					the file inode probably is much
					faster (the OS caches them) than
					accessing the first page of the file */
	ulint		id,		/* in: space id */
	const char*	name)		/* in: table name in the
					databasename/tablename format */
@@ -2540,6 +2594,12 @@ fil_open_single_table_tablespace(
		return(FALSE);
	}

	if (!check_space_id) {
		space_id = id;

		goto skip_check;
	}

	/* Read the first page of the tablespace */

	buf2 = ut_malloc(2 * UNIV_PAGE_SIZE);
@@ -2552,6 +2612,8 @@ fil_open_single_table_tablespace(

	space_id = fsp_header_get_space_id(page);

	ut_free(buf2);

	if (space_id != id) {
		ut_print_timestamp(stderr);

@@ -2572,6 +2634,7 @@ fil_open_single_table_tablespace(
		goto func_exit;
	}

skip_check:
	success = fil_space_create(filepath, space_id, FIL_TABLESPACE);

	if (!success) {
@@ -2584,7 +2647,6 @@ fil_open_single_table_tablespace(
	fil_node_create(filepath, 0, space_id, FALSE);
func_exit:
	os_file_close(file);
	ut_free(buf2);
	mem_free(filepath);

	return(ret);
@@ -2651,7 +2713,7 @@ fil_load_single_table_tablespace(
	        fprintf(stderr,
"InnoDB: Error: could not open single-table tablespace file\n"
"InnoDB: %s!\n"
"InnoDB: We do not continue crash recovery, because the table will become\n"
"InnoDB: We do not continue the crash recovery, because the table may become\n"
"InnoDB: corrupt if we cannot apply the log records in the InnoDB log to it.\n"
"InnoDB: To fix the problem and start mysqld:\n"
"InnoDB: 1) If there is a permission problem in the file and mysqld cannot\n"
@@ -2822,8 +2884,9 @@ fil_load_single_table_tablespace(
		goto func_exit;
	}

	/* We do not measure the size of the file, that is why we pass the 0
	below */
	/* We do not use the size information we have about the file, because
	the rounding formulat for extents and pages is somewhat complex; we
	let fil_node_open() do that task. */

	fil_node_create(filepath, 0, space_id, FALSE);
func_exit:
+6 −4
Original line number Diff line number Diff line
@@ -18,12 +18,14 @@ Created 4/24/1996 Heikki Tuuri
In a crash recovery we already have all the tablespace objects created.
This function compares the space id information in the InnoDB data dictionary
to what we already read with fil_load_single_table_tablespaces().
In a normal startup we just scan the biggest space id, and store it to
fil_system. */

In a normal startup, we create the tablespace objects for every table in
InnoDB's data dictionary, if the corresponding .ibd file exists.
We also scan the biggest space id, and store it to fil_system. */

void
dict_check_tablespaces_or_store_max_id(
/*===================================*/
dict_check_tablespaces_and_store_max_id(
/*====================================*/
	ibool	in_crash_recovery);	/* in: are we doing a crash recovery */
/************************************************************************
Finds the first table name in the given database. */
+19 −9
Original line number Diff line number Diff line
@@ -364,16 +364,26 @@ fil_create_new_single_table_tablespace(
					tablespace file in pages,
					must be >= FIL_IBD_FILE_INITIAL_SIZE */
/************************************************************************
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 dictionary cache. NOTE that we assume this operation is used under the
protection of the dictionary mutex, so that two users cannot race here. */
Tries to open a single-table tablespace and optionally 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 a tablespace when we start up mysqld, and also in
IMPORT TABLESPACE.
NOTE that we assume this operation is used either at the database startup
or under the protection of the dictionary mutex, so that two users cannot
race here. This operation does not leave the file associated with the
tablespace open, but closes it after we have looked at the space id in it. */

ibool
fil_open_single_table_tablespace(
/*=============================*/
					/* out: TRUE if success */
	ibool		check_space_id,	/* in: should we check that the space
					id in the file is right; we assume
					that this function runs much faster
					if no check is made, since accessing
					the file inode probably is much
					faster (the OS caches them) than
					accessing the first page of the file */
	ulint		id,		/* in: space id */
	const char*	name);		/* in: table name in the
					databasename/tablename format */
Loading