From 31143f1cf82648076cb8ab7c68653e113ce0ba31 Mon Sep 17 00:00:00 2001 From: Sergey Vojtovich <svoj@sun.com> Date: Thu, 1 Apr 2010 14:45:58 +0400 Subject: [PATCH] Applying InnoDB snapshot, fixes BUG#41609. Detailed revision comments: r6252 | marko | 2009-11-30 12:50:11 +0200 (Mon, 30 Nov 2009) | 23 lines branches/zip: Suppress errors about non-found temporary tables. Write the is_temp flag to SYS_TABLES.MIX_LEN. dict_table_t::flags: Add a flag for is_temporary, DICT_TF2_TEMPORARY. Unlike other flags, this will not be written to the tablespace flags or SYS_TABLES.TYPE, but only to SYS_TABLES.MIX_LEN. dict_build_table_def_step(): Only pass DICT_TF_BITS to tablespaces. dict_check_tablespaces_and_store_max_id(), dict_load_table(): Suppress errors about temporary tables not being found. dict_create_sys_tables_tuple(): Write the DICT_TF2_TEMPORARY flag to SYS_TABLES.MIX_LEN. fil_space_create(), fil_create_new_single_table_tablespace(): Add assertions about space->flags. row_drop_table_for_mysql(): Do not complain about non-found temporary tables. rb://160 approved by Heikki Tuuri. This addresses the second part of Bug #41609 Crash recovery does not work for InnoDB temporary tables. --- storage/innodb_plugin/ChangeLog | 10 ++ storage/innodb_plugin/dict/dict0boot.c | 3 + storage/innodb_plugin/dict/dict0crea.c | 17 ++-- storage/innodb_plugin/dict/dict0load.c | 113 +++++++++++++++------ storage/innodb_plugin/dict/dict0mem.c | 2 +- storage/innodb_plugin/fil/fil0fil.c | 9 +- storage/innodb_plugin/handler/ha_innodb.cc | 4 + storage/innodb_plugin/include/dict0mem.h | 24 ++++- storage/innodb_plugin/row/row0mysql.c | 11 +- 9 files changed, 143 insertions(+), 50 deletions(-) diff --git a/storage/innodb_plugin/ChangeLog b/storage/innodb_plugin/ChangeLog index 5ea2995a97..ac66ff1096 100644 --- a/storage/innodb_plugin/ChangeLog +++ b/storage/innodb_plugin/ChangeLog @@ -1,3 +1,13 @@ +2009-11-30 The InnoDB Team + + * dict/dict0crea.c, dict/dict0mem.c, dict/dict0load.c, + dict/dict0boot.c, fil/fil0fil.c, handler/ha_innodb.cc, + include/dict0mem.h, row/row0mysql.c: + Fix the bogus warning messages for non-existing temporary + tables that were reported in + Bug#41609 Crash recovery does not work for InnoDB temporary tables. + The actual crash recovery bug was corrected on 2009-04-29. + 2009-11-20 The InnoDB Team * handler/ha_innodb.cc: diff --git a/storage/innodb_plugin/dict/dict0boot.c b/storage/innodb_plugin/dict/dict0boot.c index e55de30481..8f948c06c5 100644 --- a/storage/innodb_plugin/dict/dict0boot.c +++ b/storage/innodb_plugin/dict/dict0boot.c @@ -274,6 +274,9 @@ dict_boot(void) and (TYPE & DICT_TF_FORMAT_MASK) are nonzero and TYPE = table->flags */ dict_mem_table_add_col(table, heap, "TYPE", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "MIX_ID", DATA_BINARY, 0, 0); + /* MIX_LEN may contain additional table flags when + ROW_FORMAT!=REDUNDANT. Currently, these flags include + DICT_TF2_TEMPORARY. */ dict_mem_table_add_col(table, heap, "MIX_LEN", DATA_INT, 0, 4); dict_mem_table_add_col(table, heap, "CLUSTER_NAME", DATA_BINARY, 0, 0); dict_mem_table_add_col(table, heap, "SPACE", DATA_INT, 0, 4); diff --git a/storage/innodb_plugin/dict/dict0crea.c b/storage/innodb_plugin/dict/dict0crea.c index 96a9bd8152..b0341e5eea 100644 --- a/storage/innodb_plugin/dict/dict0crea.c +++ b/storage/innodb_plugin/dict/dict0crea.c @@ -94,13 +94,13 @@ dict_create_sys_tables_tuple( dfield = dtuple_get_nth_field(entry, 3); ptr = mem_heap_alloc(heap, 4); - if (table->flags & ~DICT_TF_COMPACT) { + if (table->flags & (~DICT_TF_COMPACT & ~(~0 << DICT_TF_BITS))) { ut_a(table->flags & DICT_TF_COMPACT); ut_a(dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP); ut_a((table->flags & DICT_TF_ZSSIZE_MASK) <= (DICT_TF_ZSSIZE_MAX << DICT_TF_ZSSIZE_SHIFT)); - ut_a(!(table->flags & (~0 << DICT_TF_BITS))); - mach_write_to_4(ptr, table->flags); + ut_a(!(table->flags & (~0 << DICT_TF2_BITS))); + mach_write_to_4(ptr, table->flags & ~(~0 << DICT_TF_BITS)); } else { mach_write_to_4(ptr, DICT_TABLE_ORDINARY); } @@ -112,11 +112,12 @@ dict_create_sys_tables_tuple( ptr = mem_heap_zalloc(heap, 8); dfield_set_data(dfield, ptr, 8); - /* 7: MIX_LEN (obsolete) --------------------------*/ + /* 7: MIX_LEN (additional flags) --------------------------*/ dfield = dtuple_get_nth_field(entry, 5); - ptr = mem_heap_zalloc(heap, 4); + ptr = mem_heap_alloc(heap, 4); + mach_write_to_4(ptr, table->flags >> DICT_TF2_SHIFT); dfield_set_data(dfield, ptr, 4); /* 8: CLUSTER_NAME ---------------------*/ @@ -230,6 +231,7 @@ dict_build_table_def_step( dict_table_t* table; dtuple_t* row; ulint error; + ulint flags; const char* path_or_name; ibool is_path; mtr_t mtr; @@ -268,9 +270,10 @@ dict_build_table_def_step( ut_ad(!dict_table_zip_size(table) || dict_table_get_format(table) >= DICT_TF_FORMAT_ZIP); + flags = table->flags & ~(~0 << DICT_TF_BITS); error = fil_create_new_single_table_tablespace( &space, path_or_name, is_path, - table->flags == DICT_TF_COMPACT ? 0 : table->flags, + flags == DICT_TF_COMPACT ? 0 : flags, FIL_IBD_FILE_INITIAL_SIZE); table->space = (unsigned int) space; @@ -286,7 +289,7 @@ dict_build_table_def_step( mtr_commit(&mtr); } else { /* Create in the system tablespace: disallow new features */ - table->flags &= DICT_TF_COMPACT; + table->flags &= (~0 << DICT_TF_BITS) | DICT_TF_COMPACT; } row = dict_create_sys_tables_tuple(table, node->heap); diff --git a/storage/innodb_plugin/dict/dict0load.c b/storage/innodb_plugin/dict/dict0load.c index 842a129c1a..2867125e39 100644 --- a/storage/innodb_plugin/dict/dict0load.c +++ b/storage/innodb_plugin/dict/dict0load.c @@ -390,15 +390,35 @@ loop: mtr_commit(&mtr); - if (space_id != 0 && in_crash_recovery) { + if (space_id == 0) { + /* The system tablespace always exists. */ + } else if (in_crash_recovery) { /* Check that the tablespace (the .ibd file) really - exists; print a warning to the .err log if not */ - - fil_space_for_table_exists_in_mem(space_id, name, - FALSE, TRUE, TRUE); - } + exists; print a warning to the .err log if not. + Do not print warnings for temporary tables. */ + ibool is_temp; + + field = rec_get_nth_field_old(rec, 4, &len); + if (0x80000000UL & mach_read_from_4(field)) { + /* ROW_FORMAT=COMPACT: read the is_temp + flag from SYS_TABLES.MIX_LEN. */ + field = rec_get_nth_field_old(rec, 7, &len); + is_temp = mach_read_from_4(field) + & DICT_TF2_TEMPORARY; + } else { + /* For tables created with old versions + of InnoDB, SYS_TABLES.MIX_LEN may contain + garbage. Such tables would always be + in ROW_FORMAT=REDUNDANT. Pretend that + all such tables are non-temporary. That is, + do not suppress error printouts about + temporary tables not being found. */ + is_temp = FALSE; + } - if (space_id != 0 && !in_crash_recovery) { + fil_space_for_table_exists_in_mem( + space_id, name, is_temp, TRUE, !is_temp); + } else { /* It is a normal database startup: create the space object and check that the .ibd file exists. */ @@ -894,43 +914,72 @@ err_exit: (ulong) flags); goto err_exit; } + } else { + flags = 0; + } - if (fil_space_for_table_exists_in_mem(space, name, FALSE, - FALSE, FALSE)) { - /* 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_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS")); + + field = rec_get_nth_field_old(rec, 4, &len); + n_cols = mach_read_from_4(field); + + /* The high-order bit of N_COLS is the "compact format" flag. + For tables in that format, MIX_LEN may hold additional flags. */ + if (n_cols & 0x80000000UL) { + ulint flags2; + + flags |= DICT_TF_COMPACT; + + ut_a(name_of_col_is(sys_tables, sys_index, 7, "MIX_LEN")); + field = rec_get_nth_field_old(rec, 7, &len); + + flags2 = mach_read_from_4(field); + + if (flags2 & (~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT))) { + ut_print_timestamp(stderr); + fputs(" InnoDB: Warning: table ", stderr); + ut_print_filename(stderr, name); + fprintf(stderr, "\n" + "InnoDB: in InnoDB data dictionary" + " has unknown flags %lx.\n", + (ulong) flags2); + + flags2 &= ~(~0 << (DICT_TF2_BITS - DICT_TF2_SHIFT)); + } + flags |= flags2 << DICT_TF2_SHIFT; + } + + /* See if the tablespace is available. */ + if (space == 0) { + /* The system tablespace is always available. */ + } else if (!fil_space_for_table_exists_in_mem( + space, name, + (flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY, + FALSE, FALSE)) { + + if ((flags >> DICT_TF2_SHIFT) & DICT_TF2_TEMPORARY) { + /* Do not bother to retry opening temporary tables. */ + ibd_file_missing = TRUE; + } else { ut_print_timestamp(stderr); fprintf(stderr, - " InnoDB: error: space object of table %s,\n" + " InnoDB: error: space object of table"); + ut_print_filename(stderr, name); + fprintf(stderr, ",\n" "InnoDB: space id %lu did not exist in memory." " Retrying an open.\n", - name, (ulong)space); + (ulong) space); /* Try to open the tablespace */ if (!fil_open_single_table_tablespace( - TRUE, space, flags, name)) { - /* We failed to find a sensible tablespace - file */ + TRUE, space, + flags & ~(~0 << DICT_TF_BITS), name)) { + /* We failed to find a sensible + tablespace file */ ibd_file_missing = TRUE; } } - } else { - flags = 0; - } - - ut_a(name_of_col_is(sys_tables, sys_index, 4, "N_COLS")); - - field = rec_get_nth_field_old(rec, 4, &len); - n_cols = mach_read_from_4(field); - - /* The high-order bit of N_COLS is the "compact format" flag. */ - if (n_cols & 0x80000000UL) { - flags |= DICT_TF_COMPACT; } table = dict_mem_table_create(name, space, n_cols & ~0x80000000UL, diff --git a/storage/innodb_plugin/dict/dict0mem.c b/storage/innodb_plugin/dict/dict0mem.c index 6458cbab92..66b4b43f29 100644 --- a/storage/innodb_plugin/dict/dict0mem.c +++ b/storage/innodb_plugin/dict/dict0mem.c @@ -59,7 +59,7 @@ dict_mem_table_create( mem_heap_t* heap; ut_ad(name); - ut_a(!(flags & (~0 << DICT_TF_BITS))); + ut_a(!(flags & (~0 << DICT_TF2_BITS))); heap = mem_heap_create(DICT_HEAP_SIZE); diff --git a/storage/innodb_plugin/fil/fil0fil.c b/storage/innodb_plugin/fil/fil0fil.c index 112a0e27d5..b2593765af 100644 --- a/storage/innodb_plugin/fil/fil0fil.c +++ b/storage/innodb_plugin/fil/fil0fil.c @@ -1101,6 +1101,7 @@ fil_space_create( ROW_FORMAT=REDUNDANT (table->flags == 0). For any other format, the tablespace flags should equal table->flags. */ ut_a(flags != DICT_TF_COMPACT); + ut_a(!(flags & (~0UL << DICT_TF_BITS))); try_again: /*printf( @@ -2586,6 +2587,7 @@ fil_create_new_single_table_tablespace( ROW_FORMAT=REDUNDANT (table->flags == 0). For any other format, the tablespace flags should equal table->flags. */ ut_a(flags != DICT_TF_COMPACT); + ut_a(!(flags & (~0UL << DICT_TF_BITS))); path = fil_make_ibd_name(tablename, is_temp); @@ -2958,8 +2960,10 @@ fil_open_single_table_tablespace( /* The tablespace flags (FSP_SPACE_FLAGS) should be 0 for ROW_FORMAT=COMPACT (table->flags == DICT_TF_COMPACT) and ROW_FORMAT=REDUNDANT (table->flags == 0). For any other - format, the tablespace flags should equal table->flags. */ + format, the tablespace flags should be equal to + table->flags & ~(~0 << DICT_TF_BITS). */ ut_a(flags != DICT_TF_COMPACT); + ut_a(!(flags & (~0UL << DICT_TF_BITS))); file = os_file_create_simple_no_error_handling( filepath, OS_FILE_OPEN, OS_FILE_READ_ONLY, &success); @@ -3011,7 +3015,8 @@ fil_open_single_table_tablespace( ut_free(buf2); - if (UNIV_UNLIKELY(space_id != id || space_flags != flags)) { + if (UNIV_UNLIKELY(space_id != id + || space_flags != (flags & ~(~0 << DICT_TF_BITS)))) { ut_print_timestamp(stderr); fputs(" InnoDB: Error: tablespace id and flags in file ", diff --git a/storage/innodb_plugin/handler/ha_innodb.cc b/storage/innodb_plugin/handler/ha_innodb.cc index 47b8203091..f67334ac45 100644 --- a/storage/innodb_plugin/handler/ha_innodb.cc +++ b/storage/innodb_plugin/handler/ha_innodb.cc @@ -6333,6 +6333,10 @@ ha_innobase::create( goto cleanup; } + if (create_info->options & HA_LEX_CREATE_TMP_TABLE) { + flags |= DICT_TF2_TEMPORARY << DICT_TF2_SHIFT; + } + error = create_table_def(trx, form, norm_name, create_info->options & HA_LEX_CREATE_TMP_TABLE ? name2 : NULL, flags); diff --git a/storage/innodb_plugin/include/dict0mem.h b/storage/innodb_plugin/include/dict0mem.h index 2d00111193..9996fb59a7 100644 --- a/storage/innodb_plugin/include/dict0mem.h +++ b/storage/innodb_plugin/include/dict0mem.h @@ -80,21 +80,39 @@ combination of types */ /** File format */ /* @{ */ #define DICT_TF_FORMAT_SHIFT 5 /* file format */ -#define DICT_TF_FORMAT_MASK (127 << DICT_TF_FORMAT_SHIFT) +#define DICT_TF_FORMAT_MASK \ +((~(~0 << (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT))) << DICT_TF_FORMAT_SHIFT) #define DICT_TF_FORMAT_51 0 /*!< InnoDB/MySQL up to 5.1 */ #define DICT_TF_FORMAT_ZIP 1 /*!< InnoDB plugin for 5.1: compressed tables, new BLOB treatment */ /** Maximum supported file format */ #define DICT_TF_FORMAT_MAX DICT_TF_FORMAT_ZIP - +/* @} */ #define DICT_TF_BITS 6 /*!< number of flag bits */ #if (1 << (DICT_TF_BITS - DICT_TF_FORMAT_SHIFT)) <= DICT_TF_FORMAT_MAX # error "DICT_TF_BITS is insufficient for DICT_TF_FORMAT_MAX" #endif /* @} */ + +/** @brief Additional table flags. + +These flags will be stored in SYS_TABLES.MIX_LEN. All unused flags +will be written as 0. The column may contain garbage for tables +created with old versions of InnoDB that only implemented +ROW_FORMAT=REDUNDANT. */ +/* @{ */ +#define DICT_TF2_SHIFT DICT_TF_BITS + /*!< Shift value for + table->flags. */ +#define DICT_TF2_TEMPORARY 1 /*!< TRUE for tables from + CREATE TEMPORARY TABLE. */ +#define DICT_TF2_BITS (DICT_TF2_SHIFT + 1) + /*!< Total number of bits + in table->flags. */ /* @} */ + /**********************************************************************//** Creates a table memory object. @return own: table object */ @@ -374,7 +392,7 @@ struct dict_table_struct{ unsigned space:32; /*!< space where the clustered index of the table is placed */ - unsigned flags:DICT_TF_BITS;/*!< DICT_TF_COMPACT, ... */ + unsigned flags:DICT_TF2_BITS;/*!< DICT_TF_COMPACT, ... */ unsigned ibd_file_missing:1; /*!< TRUE if this is in a single-table tablespace and the .ibd file is missing; then diff --git a/storage/innodb_plugin/row/row0mysql.c b/storage/innodb_plugin/row/row0mysql.c index 181c39de88..7a43d0f3b9 100644 --- a/storage/innodb_plugin/row/row0mysql.c +++ b/storage/innodb_plugin/row/row0mysql.c @@ -3264,7 +3264,7 @@ check_next_foreign: ut_error; } else { - ibool is_path; + ibool is_temp; const char* name_or_path; mem_heap_t* heap; @@ -3277,12 +3277,13 @@ check_next_foreign: space_id = table->space; if (table->dir_path_of_temp_table != NULL) { - is_path = TRUE; name_or_path = mem_heap_strdup( heap, table->dir_path_of_temp_table); + is_temp = TRUE; } else { - is_path = FALSE; name_or_path = name; + is_temp = (table->flags >> DICT_TF2_SHIFT) + & DICT_TF2_TEMPORARY; } dict_table_remove_from_cache(table); @@ -3302,8 +3303,8 @@ check_next_foreign: if (err == DB_SUCCESS && space_id > 0) { if (!fil_space_for_table_exists_in_mem(space_id, name_or_path, - is_path, - FALSE, TRUE)) { + is_temp, FALSE, + !is_temp)) { err = DB_SUCCESS; fprintf(stderr, -- 2.30.9